mirror of
https://github.com/cowmonk/cowos.git
synced 2025-10-27 14:33:27 +00:00
cowos moves to 64bit! and framebuffers too ig
This commit is contained in:
parent
b78e4fc24d
commit
babc65305d
32 changed files with 4074 additions and 146 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
cowos.iso
|
||||
kernel/bin/
|
||||
limine/
|
||||
isodir/boot/limine/limine-bios.sys
|
||||
isodir/boot/limine/limine-bios-cd.bin
|
||||
isodir/boot/limine/limine-uefi-cd.bin
|
||||
isodir/EFI/BOOT/BOOTX64.EFI
|
||||
isodir/EFI/BOOT/BOOTIA32.EFI
|
||||
28
Makefile
Normal file
28
Makefile
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
all: iso
|
||||
|
||||
iso: kernel limine
|
||||
cp -v ./kernel/bin/cowos ./isodir/boot/
|
||||
|
||||
xorriso -as mkisofs -R -r -J -b boot/limine/limine-bios-cd.bin \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus \
|
||||
-apm-block-size 2048 --efi-boot boot/limine/limine-uefi-cd.bin \
|
||||
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||
isodir -o cowos.iso
|
||||
|
||||
./limine/limine bios-install cowos.iso
|
||||
|
||||
kernel:
|
||||
make -C ./kernel/ all
|
||||
|
||||
limine:
|
||||
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
|
||||
make -C limine
|
||||
|
||||
cp -v limine/limine-bios.sys limine/limine-bios-cd.bin \
|
||||
limine/limine-uefi-cd.bin isodir/boot/limine/
|
||||
|
||||
cp -v limine/BOOTX64.EFI isodir/EFI/BOOT/
|
||||
cp -v limine/BOOTIA32.EFI isodir/EFI/BOOT/
|
||||
|
||||
clean:
|
||||
rm cowos.iso
|
||||
38
README.md
38
README.md
|
|
@ -4,30 +4,24 @@
|
|||
Custom OS from scratch in C
|
||||
|
||||
# Notes
|
||||
This only supports 32bit for now, please DO NOT compile with 64bit or it'll fail to boot
|
||||
**Heavily UNDER DEVELOPMENT**
|
||||
|
||||
## compilation of any component
|
||||
You are required to get your own cross C compiler. This is because normal C compilers for your Linux distro (assuming that you are on Linux) will optimize against your own libs and other things. This OS doesn't exist yet, so this is a big no no in OS development. Another thing is that you want to compile for 32 bit, so you'll need to cross compile anyways...
|
||||
Currently just boots and well, does nothing lol.
|
||||
|
||||
### general c files
|
||||
## BUILDING
|
||||
You'll need a few things:
|
||||
- LLVM/Clang (default C compiler)
|
||||
- LLD (linker)
|
||||
- xorriso (iso creation)
|
||||
- git
|
||||
- make
|
||||
- qemu (for virtual machine)
|
||||
|
||||
After acquiring those just run make and it'll do everything for you:
|
||||
```bash
|
||||
i386-elf-gcc -c kernel.c -o kernel.o -std=c99 -ffreestanding -O2 -Wall -Wextra # i386 is the 32 bit version of x86
|
||||
# also please compile with the -Iinclude flag to include the libraries like string.h in the arch
|
||||
make
|
||||
```
|
||||
|
||||
### "compiling" the "boot stub"
|
||||
```bash
|
||||
i386-elf-as boot.s -o boot.o
|
||||
```
|
||||
|
||||
### linking the "compiled" boot stub w/compiled kernel img
|
||||
```
|
||||
i386-elf-gcc -T linker.ld -o cowos.bin -ffreestanding -O2 -nostdlib boot.o kernel.o
|
||||
```
|
||||
|
||||
## Getting it bootable
|
||||
You'll need grub and mtools. First move the compiled cowos.bin to isodir/boot. Then run the following command:
|
||||
```bash
|
||||
grub-mkrescue isodir/ -o cowos.iso
|
||||
```
|
||||
Now you can enjoy running this in qemu lol.
|
||||
# Credits
|
||||
- [nolibc](https://github.com/wtarreau/nolibc): libc-less wrapper to make tiny static executables for simple programs.
|
||||
- [Limine](https://github.com/limine-bootloader/limine): modern, advanced, portable, multiprotocol bootloader and boot manager.
|
||||
|
|
|
|||
BIN
isodir/boot/cowos
Executable file
BIN
isodir/boot/cowos
Executable file
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
menuentry "cowos" {
|
||||
multiboot /boot/kernel.elf
|
||||
}
|
||||
58
kernel/Makefile
Normal file
58
kernel/Makefile
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
override OUTPUT := cowos
|
||||
|
||||
CC := clang
|
||||
|
||||
CFLAGS := -g -O3 -pipe
|
||||
|
||||
CPPFLAGS :=
|
||||
|
||||
override CFLAGS += \
|
||||
-m64 -g -c -ffreestanding -Wall -Werror -fcommon -Iinclude/ -fPIE -mno-80387 \
|
||||
-mno-mmx \
|
||||
-mno-sse \
|
||||
-nostdlib \
|
||||
-mno-sse2 \
|
||||
-mno-red-zone -fno-stack-protector \
|
||||
-fno-stack-check \
|
||||
-fno-lto \
|
||||
-target x86_64-unknown-none
|
||||
|
||||
override CPPFLAGS := \
|
||||
-I src \
|
||||
$(CPPFLAGS) \
|
||||
-DLIMINE_API_REVISION=3 \
|
||||
-MMD \
|
||||
-MP
|
||||
|
||||
override NASMFLAGS += \
|
||||
-Wall \
|
||||
-f elf64
|
||||
|
||||
override LDFLAGS += \
|
||||
-Wl,-m,elf_x86_64 \
|
||||
-Wl,--build-id=none \
|
||||
-nostdlib \
|
||||
-static \
|
||||
-z max-page-size=0x1000 \
|
||||
-T linker.ld
|
||||
|
||||
C_SOURCES = $(shell find . -name '*.c')
|
||||
C_OBJS = $(patsubst %.c,%.o,$(C_SOURCES))
|
||||
|
||||
.PHONY: all
|
||||
all: bin/$(OUTPUT)
|
||||
|
||||
bin/$(OUTPUT): Makefile $(C_OBJS) linker.ld
|
||||
mkdir ./bin/ -p
|
||||
$(CC) $(LDFLAGS) -o ./bin/$(OUTPUT) $(C_OBJS) -fuse-ld=lld
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(subst .o,.c,$@) -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
find . -name '*.o' -delete
|
||||
rm -r -f ./bin
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
|
||||
.set MEMINFO, 1<<1 /* provide memory map */
|
||||
.set FLAGS, ALIGN | MEMINFO /* Multiboot flag */
|
||||
.set MAGIC, 0x1BADB002 /* Magic number lets bootloader find the header */
|
||||
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot (sanity check I think) */
|
||||
|
||||
/* so this basically declares the multiboot header that defines this program as a kernel,
|
||||
and the following values are in the multiboot standard. The bootloader will look for the
|
||||
first 8KiB of the kernel file, aligned with the 32-bit boundary, this means that it won't
|
||||
work with 64bit until I keep on learning or I create my own bootloader (without multiboot)
|
||||
*/
|
||||
.section .multiboot
|
||||
.align 4
|
||||
.long MAGIC
|
||||
.long FLAGS
|
||||
.long CHECKSUM
|
||||
|
||||
/* This is where my knowledge is not high enough but here is the summary:
|
||||
- esp is NOT in the multiboot standard so the kernel has to provide it.
|
||||
this basically means that it doesn't define the value of the stack register
|
||||
(whatever that means)
|
||||
- This allocates some room for a stack by creating a symbol at the bottom of it
|
||||
then allocate 16 KiB and then creating a symbol on top.
|
||||
- The stack grows downwards on x86.
|
||||
|
||||
And many more, apparently it's re-aligned to System-V ABI standard as well? Not sure, but hopefully I can
|
||||
continue learning
|
||||
*/
|
||||
.section .bss
|
||||
.align 16
|
||||
stack_bottom:
|
||||
.skip 16384 # 16 KiB
|
||||
stack_top:
|
||||
|
||||
/* linker specifies a _start as the entry point to the kernel and the bootloader will jump to the position
|
||||
however it doesn't make any sense to return to this after the bootloader is gone
|
||||
*/
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
/* We are now in... no printf and other things, kernel has FULL CONTROL of the cpu. No security also lol */
|
||||
|
||||
/* To set up a stack, this sets the esp to register to the point of the stack because it grows downwards on
|
||||
on x86 systems. this is done in assembly because languages like C can't function without a stack */
|
||||
mov $stack_top, %esp
|
||||
|
||||
/* so we need to initialize some critical processor states before the high-level kernel is entered.
|
||||
interestingly a lot of things are done at the boot level, we should load GDT, enable paging, and add runtime
|
||||
support (for C++). Crazy!
|
||||
*/
|
||||
|
||||
/* time to enter the kernel,
|
||||
according to the guide, this is a well defined call as the stack was originally 16-byte aligned, we pushed a
|
||||
multiple of 16-bytes to the stack (since 0 bytes were pushed so far), so alignment has been perserved.
|
||||
*/
|
||||
call kernel_main
|
||||
|
||||
/* If there is nothing else to do, the computer will be in an infinite loop
|
||||
- Disable interrupts with cli (they wil be disabled by the bootloader)
|
||||
- Wait for next interrupt to arrive with halt instruction (hlt)
|
||||
- Jump to hlt instruction if it ever wakes up due to a non-maskable
|
||||
interrupt occuring or due to system management mode.
|
||||
*/
|
||||
cli
|
||||
1: hlt
|
||||
jmp 1b
|
||||
|
||||
/* set the size of _start symbol to the current location minus its start.
|
||||
Useful for debugging or if I implement call tracing
|
||||
*/
|
||||
.size _start, . - _start
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
ENTRY(_start) /* Entry point symbol */
|
||||
|
||||
SECTIONS {
|
||||
/* Load address in memory: 2MB for kernel */
|
||||
. = 2M;
|
||||
|
||||
/* Multiboot header must be in the first 8KB of the file and 32-bit aligned */
|
||||
.text BLOCK(4K) : ALIGN(4K) {
|
||||
*(.multiboot)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.rodata BLOCK(4K) : ALIGN(4K) {
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.data BLOCK(4K) : ALIGN(4K) {
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss BLOCK(4K) : ALIGN(4K) {
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
#include <drivers/video/vga.h>
|
||||
/* #include <bootloader.h> */
|
||||
#include <string.h>
|
||||
|
||||
/* for frame buffer
|
||||
static volatile struct limine_framebuffer_request limineFBreq = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0};
|
||||
*/
|
||||
|
||||
size_t term_row;
|
||||
size_t term_col;
|
||||
uint8_t term_color;
|
||||
|
|
|
|||
BIN
kernel/drivers/video/vga.o
Normal file
BIN
kernel/drivers/video/vga.o
Normal file
Binary file not shown.
21
kernel/include/bootloader.h
Normal file
21
kernel/include/bootloader.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef BOOTLOADER_H
|
||||
#define BOOTLOADER_H
|
||||
|
||||
#include "limine.h"
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
static volatile LIMINE_BASE_REVISION(3);
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
static volatile struct limine_framebuffer_request framebuffer_request = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests_start")))
|
||||
static volatile LIMINE_REQUESTS_START_MARKER
|
||||
|
||||
__attribute__((used, section(".limine_requests_end")))
|
||||
static volatile LIMINE_REQUESTS_END_MARKER;
|
||||
|
||||
#endif /* BOOTLOADER_H */
|
||||
|
|
@ -22,7 +22,7 @@ enum vga_color {
|
|||
VGA_COLOR_LIGHT_MAGENTA = 13,
|
||||
VGA_COLOR_LIGHT_BROWN = 14,
|
||||
VGA_COLOR_WHITE = 15,
|
||||
}
|
||||
};
|
||||
|
||||
static inline uint8_t
|
||||
vga_entry_color(enum vga_color fg, enum vga_color bg)
|
||||
|
|
@ -39,7 +39,7 @@ vga_entry(unsigned char uc, uint8_t color)
|
|||
/* using mode 3 of VGA 80x25 */
|
||||
#define VGA_WIDTH 80
|
||||
#define VGA_HEIGHT 25
|
||||
#define VGA_MEMORY 0xB8000 /* VGA memory location */
|
||||
#define VGA_MEMORY 0xA0000 /* VGA memory location */
|
||||
|
||||
void term_init(void);
|
||||
void term_setcolor(uint8_t color);
|
||||
|
|
|
|||
22
kernel/include/fb.h
Normal file
22
kernel/include/fb.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef FB_H
|
||||
#define FB_H
|
||||
|
||||
/* *pixel = vram + y*pitch + x*pixelwidth */
|
||||
|
||||
/*
|
||||
| width | how many pixels you have on a horizontal line |
|
||||
|===========================================================================|
|
||||
| height | how many horizontal lines of pixels are present |
|
||||
|===========================================================================|
|
||||
| pitch | how many bytes of VRAM you should skip to go one pixel down |
|
||||
|===========================================================================|
|
||||
| depth | how many bits of color you have |
|
||||
|===========================================================================|
|
||||
| pixelwidth | how many bytes of VRAM you should skip to go one pixel right |
|
||||
*/
|
||||
|
||||
#include <klibc/types.h>
|
||||
|
||||
void putpixel(int pos_x, int pos_y, unsigned char VGA_COLOR);
|
||||
|
||||
#endif /* FB_H */
|
||||
235
kernel/include/klibc/arch.h
Normal file
235
kernel/include/klibc/arch.h
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* x86_64 specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_H
|
||||
#define _NOLIBC_ARCH_H
|
||||
|
||||
/* O_* macros for fcntl/open are architecture-specific */
|
||||
#define O_RDONLY 0
|
||||
#define O_WRONLY 1
|
||||
#define O_RDWR 2
|
||||
#define O_CREAT 0x40
|
||||
#define O_EXCL 0x80
|
||||
#define O_NOCTTY 0x100
|
||||
#define O_TRUNC 0x200
|
||||
#define O_APPEND 0x400
|
||||
#define O_NONBLOCK 0x800
|
||||
#define O_DIRECTORY 0x10000
|
||||
|
||||
/* The struct returned by the stat() syscall, equivalent to stat64(). The
|
||||
* syscall returns 116 bytes and stops in the middle of __unused.
|
||||
*/
|
||||
struct sys_stat_struct {
|
||||
unsigned long st_dev;
|
||||
unsigned long st_ino;
|
||||
unsigned long st_nlink;
|
||||
unsigned int st_mode;
|
||||
unsigned int st_uid;
|
||||
|
||||
unsigned int st_gid;
|
||||
unsigned int __pad0;
|
||||
unsigned long st_rdev;
|
||||
long st_size;
|
||||
long st_blksize;
|
||||
|
||||
long st_blocks;
|
||||
unsigned long st_atime;
|
||||
unsigned long st_atime_nsec;
|
||||
unsigned long st_mtime;
|
||||
|
||||
unsigned long st_mtime_nsec;
|
||||
unsigned long st_ctime;
|
||||
unsigned long st_ctime_nsec;
|
||||
long __unused[3];
|
||||
};
|
||||
|
||||
/* Syscalls for x86_64 :
|
||||
* - registers are 64-bit
|
||||
* - syscall number is passed in rax
|
||||
* - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively
|
||||
* - the system call is performed by calling the syscall instruction
|
||||
* - syscall return comes in rax
|
||||
* - rcx and r11 are clobbered, others are preserved.
|
||||
* - the arguments are cast to long and assigned into the target registers
|
||||
* which are then simply passed as registers to the asm code, so that we
|
||||
* don't have to experience issues with register constraints.
|
||||
* - the syscall number is always specified last in order to allow to force
|
||||
* some registers before (gcc refuses a %-register at the last position).
|
||||
* - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1
|
||||
* Calling Conventions.
|
||||
*
|
||||
* Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI
|
||||
*
|
||||
*/
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num asm("rax") = (num); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num asm("rax") = (num); \
|
||||
register long _arg1 asm("rdi") = (long)(arg1); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num asm("rax") = (num); \
|
||||
register long _arg1 asm("rdi") = (long)(arg1); \
|
||||
register long _arg2 asm("rsi") = (long)(arg2); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num asm("rax") = (num); \
|
||||
register long _arg1 asm("rdi") = (long)(arg1); \
|
||||
register long _arg2 asm("rsi") = (long)(arg2); \
|
||||
register long _arg3 asm("rdx") = (long)(arg3); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num asm("rax") = (num); \
|
||||
register long _arg1 asm("rdi") = (long)(arg1); \
|
||||
register long _arg2 asm("rsi") = (long)(arg2); \
|
||||
register long _arg3 asm("rdx") = (long)(arg3); \
|
||||
register long _arg4 asm("r10") = (long)(arg4); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num asm("rax") = (num); \
|
||||
register long _arg1 asm("rdi") = (long)(arg1); \
|
||||
register long _arg2 asm("rsi") = (long)(arg2); \
|
||||
register long _arg3 asm("rdx") = (long)(arg3); \
|
||||
register long _arg4 asm("r10") = (long)(arg4); \
|
||||
register long _arg5 asm("r8") = (long)(arg5); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num asm("rax") = (num); \
|
||||
register long _arg1 asm("rdi") = (long)(arg1); \
|
||||
register long _arg2 asm("rsi") = (long)(arg2); \
|
||||
register long _arg3 asm("rdx") = (long)(arg3); \
|
||||
register long _arg4 asm("r10") = (long)(arg4); \
|
||||
register long _arg5 asm("r8") = (long)(arg5); \
|
||||
register long _arg6 asm("r9") = (long)(arg6); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_arg6), "0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
/* startup code */
|
||||
/*
|
||||
* x86-64 System V ABI mandates:
|
||||
* 1) %rsp must be 16-byte aligned right before the function call.
|
||||
* 2) The deepest stack frame should be zero (the %rbp).
|
||||
*
|
||||
*/
|
||||
asm(".section .text\n"
|
||||
".weak _start\n"
|
||||
".global _start\n"
|
||||
"_start:\n"
|
||||
"pop %rdi\n" // argc (first arg, %rdi)
|
||||
"mov %rsp, %rsi\n" // argv[] (second arg, %rsi)
|
||||
"lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx)
|
||||
"xor %ebp, %ebp\n" // zero the stack frame
|
||||
"and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned before call
|
||||
"call main\n" // main() returns the status code, we'll exit with it.
|
||||
"mov %eax, %edi\n" // retrieve exit code (32 bit)
|
||||
"mov $60, %eax\n" // NR_exit == 60
|
||||
"syscall\n" // really exit
|
||||
"hlt\n" // ensure it does not return
|
||||
"");
|
||||
|
||||
#endif // _NOLIBC_ARCH_H
|
||||
118
kernel/include/klibc/ctype.h
Normal file
118
kernel/include/klibc/ctype.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* ctype function definitions for NOLIBC
|
||||
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_CTYPE_H
|
||||
#define _NOLIBC_CTYPE_H
|
||||
|
||||
#include "std.h"
|
||||
|
||||
/*
|
||||
* As much as possible, please keep functions alphabetically sorted.
|
||||
*/
|
||||
|
||||
static __attribute__((unused))
|
||||
int isascii(int c)
|
||||
{
|
||||
/* 0x00..0x7f */
|
||||
return (unsigned int)c <= 0x7f;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isblank(int c)
|
||||
{
|
||||
return c == '\t' || c == ' ';
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int iscntrl(int c)
|
||||
{
|
||||
/* 0x00..0x1f, 0x7f */
|
||||
return (unsigned int)c < 0x20 || c == 0x7f;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isdigit(int c)
|
||||
{
|
||||
return (unsigned int)(c - '0') < 10;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isgraph(int c)
|
||||
{
|
||||
/* 0x21..0x7e */
|
||||
return (unsigned int)(c - 0x21) < 0x5e;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int islower(int c)
|
||||
{
|
||||
return (unsigned int)(c - 'a') < 26;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isprint(int c)
|
||||
{
|
||||
/* 0x20..0x7e */
|
||||
return (unsigned int)(c - 0x20) < 0x5f;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isspace(int c)
|
||||
{
|
||||
/* \t is 0x9, \n is 0xA, \v is 0xB, \f is 0xC, \r is 0xD */
|
||||
return ((unsigned int)c == ' ') || (unsigned int)(c - 0x09) < 5;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isupper(int c)
|
||||
{
|
||||
return (unsigned int)(c - 'A') < 26;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isxdigit(int c)
|
||||
{
|
||||
return isdigit(c) || (unsigned int)(c - 'A') < 6 || (unsigned int)(c - 'a') < 6;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isalpha(int c)
|
||||
{
|
||||
return islower(c) || isupper(c);
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int isalnum(int c)
|
||||
{
|
||||
return isalpha(c) || isdigit(c);
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int ispunct(int c)
|
||||
{
|
||||
return isgraph(c) && !isalnum(c);
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CTYPE_H */
|
||||
46
kernel/include/klibc/errno.h
Normal file
46
kernel/include/klibc/errno.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Minimal errno definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ERRNO_H
|
||||
#define _NOLIBC_ERRNO_H
|
||||
|
||||
#include <asm/errno.h>
|
||||
|
||||
/* this way it will be removed if unused */
|
||||
static int errno;
|
||||
|
||||
#ifndef NOLIBC_IGNORE_ERRNO
|
||||
#define SET_ERRNO(v) do { errno = (v); } while (0)
|
||||
#else
|
||||
#define SET_ERRNO(v) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/* errno codes all ensure that they will not conflict with a valid pointer
|
||||
* because they all correspond to the highest addressable memory page.
|
||||
*/
|
||||
#define MAX_ERRNO 4095
|
||||
|
||||
#endif /* _NOLIBC_ERRNO_H */
|
||||
130
kernel/include/klibc/nolibc.h
Normal file
130
kernel/include/klibc/nolibc.h
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is designed to be used as a libc alternative for minimal programs
|
||||
* with very limited requirements. It consists of a small number of syscall and
|
||||
* type definitions, and the minimal startup code needed to call main().
|
||||
* All syscalls are declared as static functions so that they can be optimized
|
||||
* away by the compiler when not used.
|
||||
*
|
||||
* Syscalls are split into 3 levels:
|
||||
* - The lower level is the arch-specific syscall() definition, consisting in
|
||||
* assembly code in compound expressions. These are called my_syscall0() to
|
||||
* my_syscall6() depending on the number of arguments. The MIPS
|
||||
* implementation is limited to 5 arguments. All input arguments are cast
|
||||
* to a long stored in a register. These expressions always return the
|
||||
* syscall's return value as a signed long value which is often either a
|
||||
* pointer or the negated errno value.
|
||||
*
|
||||
* - The second level is mostly architecture-independent. It is made of
|
||||
* static functions called sys_<name>() which rely on my_syscallN()
|
||||
* depending on the syscall definition. These functions are responsible
|
||||
* for exposing the appropriate types for the syscall arguments (int,
|
||||
* pointers, etc) and for setting the appropriate return type (often int).
|
||||
* A few of them are architecture-specific because the syscalls are not all
|
||||
* mapped exactly the same among architectures. For example, some archs do
|
||||
* not implement select() and need pselect6() instead, so the sys_select()
|
||||
* function will have to abstract this.
|
||||
*
|
||||
* - The third level is the libc call definition. It exposes the lower raw
|
||||
* sys_<name>() calls in a way that looks like what a libc usually does,
|
||||
* takes care of specific input values, and of setting errno upon error.
|
||||
* There can be minor variations compared to standard libc calls. For
|
||||
* example the open() call always takes 3 args here.
|
||||
*
|
||||
* The errno variable is declared static and unused. This way it can be
|
||||
* optimized away if not used. However this means that a program made of
|
||||
* multiple C files may observe different errno values (one per C file). For
|
||||
* the type of programs this project targets it usually is not a problem. The
|
||||
* resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO
|
||||
* macro, in which case the errno value will never be assigned.
|
||||
*
|
||||
* Some stdint-like integer types are defined. These are valid on all currently
|
||||
* supported architectures, because signs are enforced, ints are assumed to be
|
||||
* 32 bits, longs the size of a pointer and long long 64 bits. If more
|
||||
* architectures have to be supported, this may need to be adapted.
|
||||
*
|
||||
* Some macro definitions like the O_* values passed to open(), and some
|
||||
* structures like the sys_stat struct depend on the architecture.
|
||||
*
|
||||
* The definitions start with the architecture-specific parts, which are picked
|
||||
* based on what the compiler knows about the target architecture, and are
|
||||
* completed with the generic code. Since it is the compiler which sets the
|
||||
* target architecture, cross-compiling normally works out of the box without
|
||||
* having to specify anything.
|
||||
*
|
||||
* Finally some very common libc-level functions are provided. It is the case
|
||||
* for a few functions usually found in string.h, ctype.h, or stdlib.h.
|
||||
*
|
||||
* The nolibc.h file is only a convenient entry point which includes all other
|
||||
* files. It also defines the NOLIBC macro, so that it is possible for a
|
||||
* program to check this macro to know if it is being built against and decide
|
||||
* to disable some features or simply not to include some standard libc files.
|
||||
*
|
||||
* A simple static executable may be built this way :
|
||||
* $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
|
||||
* -static -include nolibc.h -o hello hello.c -lgcc
|
||||
*
|
||||
* Simple programs meant to be reasonably portable to various libc and using
|
||||
* only a few common includes, may also be built by simply making the include
|
||||
* path point to the nolibc directory:
|
||||
* $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
|
||||
* -I../nolibc -o hello hello.c -lgcc
|
||||
*
|
||||
* The available standard (but limited) include files are:
|
||||
* ctype.h, errno.h, signal.h, stdio.h, stdlib.h, string.h, time.h
|
||||
*
|
||||
* In addition, the following ones are expected to be provided by the compiler:
|
||||
* float.h, stdarg.h, stddef.h
|
||||
*
|
||||
* The following ones which are part to the C standard are not provided:
|
||||
* assert.h, locale.h, math.h, setjmp.h, limits.h
|
||||
*
|
||||
* A very useful calling convention table may be found here :
|
||||
* http://man7.org/linux/man-pages/man2/syscall.2.html
|
||||
*
|
||||
* This doc is quite convenient though not necessarily up to date :
|
||||
* https://w3challs.com/syscalls/
|
||||
*
|
||||
*/
|
||||
#ifndef _NOLIBC_H
|
||||
#define _NOLIBC_H
|
||||
|
||||
#include "std.h"
|
||||
#include "arch.h"
|
||||
#include "types.h"
|
||||
#include "sys.h"
|
||||
#include "ctype.h"
|
||||
#include "signal.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include "time.h"
|
||||
#include "unistd.h"
|
||||
|
||||
/* Used by programs to avoid std includes */
|
||||
#define NOLIBC
|
||||
|
||||
#endif /* _NOLIBC_H */
|
||||
41
kernel/include/klibc/signal.h
Normal file
41
kernel/include/klibc/signal.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* signal function definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_SIGNAL_H
|
||||
#define _NOLIBC_SIGNAL_H
|
||||
|
||||
#include "std.h"
|
||||
#include "arch.h"
|
||||
#include "types.h"
|
||||
#include "sys.h"
|
||||
|
||||
/* This one is not marked static as it's needed by libgcc for divide by zero */
|
||||
__attribute__((weak,unused,section(".text.nolibc_raise")))
|
||||
int raise(int signal)
|
||||
{
|
||||
return sys_kill(sys_getpid(), signal);
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_SIGNAL_H */
|
||||
68
kernel/include/klibc/std.h
Normal file
68
kernel/include/klibc/std.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Standard definitions and types for NOLIBC
|
||||
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_STD_H
|
||||
#define _NOLIBC_STD_H
|
||||
|
||||
/* Declare a few quite common macros and types that usually are in stdlib.h,
|
||||
* stdint.h, ctype.h, unistd.h and a few other common locations. Please place
|
||||
* integer type definitions and generic macros here, but avoid OS-specific and
|
||||
* syscall-specific stuff, as this file is expected to be included very early.
|
||||
*/
|
||||
|
||||
/* note: may already be defined */
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
/* stdint types */
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed int int32_t;
|
||||
// typedef unsigned long long uint64_t;
|
||||
// typedef signed long long int64_t;
|
||||
typedef unsigned long size_t;
|
||||
typedef signed long ssize_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
typedef signed long intptr_t;
|
||||
typedef signed long ptrdiff_t;
|
||||
|
||||
/* those are commonly provided by sys/types.h */
|
||||
typedef unsigned int dev_t;
|
||||
typedef unsigned long ino_t;
|
||||
typedef unsigned int mode_t;
|
||||
typedef signed int pid_t;
|
||||
typedef unsigned int uid_t;
|
||||
typedef unsigned int gid_t;
|
||||
typedef unsigned long nlink_t;
|
||||
typedef signed long off_t;
|
||||
typedef signed long blksize_t;
|
||||
typedef signed long blkcnt_t;
|
||||
typedef signed long time_t;
|
||||
|
||||
#endif /* _NOLIBC_STD_H */
|
||||
325
kernel/include/klibc/stdio.h
Normal file
325
kernel/include/klibc/stdio.h
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* minimal stdio function definitions for NOLIBC
|
||||
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_STDIO_H
|
||||
#define _NOLIBC_STDIO_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "std.h"
|
||||
#include "arch.h"
|
||||
#include "errno.h"
|
||||
#include "types.h"
|
||||
#include "sys.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
/* just define FILE as a non-empty type */
|
||||
typedef struct FILE {
|
||||
char dummy[1];
|
||||
} FILE;
|
||||
|
||||
/* We define the 3 common stdio files as constant invalid pointers that
|
||||
* are easily recognized.
|
||||
*/
|
||||
static __attribute__((unused)) FILE* const stdin = (FILE*)-3;
|
||||
static __attribute__((unused)) FILE* const stdout = (FILE*)-2;
|
||||
static __attribute__((unused)) FILE* const stderr = (FILE*)-1;
|
||||
|
||||
/* getc(), fgetc(), getchar() */
|
||||
|
||||
#define getc(stream) fgetc(stream)
|
||||
|
||||
static __attribute__((unused))
|
||||
int fgetc(FILE* stream)
|
||||
{
|
||||
unsigned char ch;
|
||||
int fd;
|
||||
|
||||
if (stream < stdin || stream > stderr)
|
||||
return EOF;
|
||||
|
||||
fd = 3 + (long)stream;
|
||||
|
||||
if (read(fd, &ch, 1) <= 0)
|
||||
return EOF;
|
||||
return ch;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int getchar(void)
|
||||
{
|
||||
return fgetc(stdin);
|
||||
}
|
||||
|
||||
|
||||
/* putc(), fputc(), putchar() */
|
||||
|
||||
#define putc(c, stream) fputc(c, stream)
|
||||
|
||||
static __attribute__((unused))
|
||||
int fputc(int c, FILE* stream)
|
||||
{
|
||||
unsigned char ch = c;
|
||||
int fd;
|
||||
|
||||
if (stream < stdin || stream > stderr)
|
||||
return EOF;
|
||||
|
||||
fd = 3 + (long)stream;
|
||||
|
||||
if (write(fd, &ch, 1) <= 0)
|
||||
return EOF;
|
||||
return ch;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int putchar(int c)
|
||||
{
|
||||
return fputc(c, stdout);
|
||||
}
|
||||
|
||||
|
||||
/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
|
||||
|
||||
/* internal fwrite()-like function which only takes a size and returns 0 on
|
||||
* success or EOF on error. It automatically retries on short writes.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int _fwrite(const void *buf, size_t size, FILE *stream)
|
||||
{
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
|
||||
if (stream < stdin || stream > stderr)
|
||||
return EOF;
|
||||
|
||||
fd = 3 + (long)stream;
|
||||
|
||||
while (size) {
|
||||
ret = write(fd, buf, size);
|
||||
if (ret <= 0)
|
||||
return EOF;
|
||||
size -= ret;
|
||||
buf += ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
|
||||
{
|
||||
size_t written;
|
||||
|
||||
for (written = 0; written < nmemb; written++) {
|
||||
if (_fwrite(s, size, stream) != 0)
|
||||
break;
|
||||
s += size;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int fputs(const char *s, FILE *stream)
|
||||
{
|
||||
return _fwrite(s, strlen(s), stream);
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int puts(const char *s)
|
||||
{
|
||||
if (fputs(s, stdout) == EOF)
|
||||
return EOF;
|
||||
return putchar('\n');
|
||||
}
|
||||
|
||||
|
||||
/* fgets() */
|
||||
static __attribute__((unused))
|
||||
char *fgets(char *s, int size, FILE *stream)
|
||||
{
|
||||
int ofs;
|
||||
int c;
|
||||
|
||||
for (ofs = 0; ofs + 1 < size;) {
|
||||
c = fgetc(stream);
|
||||
if (c == EOF)
|
||||
break;
|
||||
s[ofs++] = c;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
if (ofs < size)
|
||||
s[ofs] = 0;
|
||||
return ofs ? s : NULL;
|
||||
}
|
||||
|
||||
|
||||
/* minimal vfprintf(). It supports the following formats:
|
||||
* - %[l*]{d,u,c,x,p}
|
||||
* - %s
|
||||
* - unknown modifiers are ignored.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int vfprintf(FILE *stream, const char *fmt, va_list args)
|
||||
{
|
||||
char escape, lpref, c;
|
||||
unsigned long long v;
|
||||
unsigned int written;
|
||||
size_t len, ofs;
|
||||
char tmpbuf[21];
|
||||
const char *outstr;
|
||||
|
||||
written = ofs = escape = lpref = 0;
|
||||
while (1) {
|
||||
c = fmt[ofs++];
|
||||
|
||||
if (escape) {
|
||||
/* we're in an escape sequence, ofs == 1 */
|
||||
escape = 0;
|
||||
if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
|
||||
char *out = tmpbuf;
|
||||
|
||||
if (c == 'p')
|
||||
v = va_arg(args, unsigned long);
|
||||
else if (lpref) {
|
||||
if (lpref > 1)
|
||||
v = va_arg(args, unsigned long long);
|
||||
else
|
||||
v = va_arg(args, unsigned long);
|
||||
} else
|
||||
v = va_arg(args, unsigned int);
|
||||
|
||||
if (c == 'd') {
|
||||
/* sign-extend the value */
|
||||
if (lpref == 0)
|
||||
v = (long long)(int)v;
|
||||
else if (lpref == 1)
|
||||
v = (long long)(long)v;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'c':
|
||||
out[0] = v;
|
||||
out[1] = 0;
|
||||
break;
|
||||
case 'd':
|
||||
i64toa_r(v, out);
|
||||
break;
|
||||
case 'u':
|
||||
u64toa_r(v, out);
|
||||
break;
|
||||
case 'p':
|
||||
*(out++) = '0';
|
||||
*(out++) = 'x';
|
||||
/* fall through */
|
||||
default: /* 'x' and 'p' above */
|
||||
u64toh_r(v, out);
|
||||
break;
|
||||
}
|
||||
outstr = tmpbuf;
|
||||
}
|
||||
else if (c == 's') {
|
||||
outstr = va_arg(args, char *);
|
||||
if (!outstr)
|
||||
outstr="(null)";
|
||||
}
|
||||
else if (c == '%') {
|
||||
/* queue it verbatim */
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
/* modifiers or final 0 */
|
||||
if (c == 'l') {
|
||||
/* long format prefix, maintain the escape */
|
||||
lpref++;
|
||||
}
|
||||
escape = 1;
|
||||
goto do_escape;
|
||||
}
|
||||
len = strlen(outstr);
|
||||
goto flush_str;
|
||||
}
|
||||
|
||||
/* not an escape sequence */
|
||||
if (c == 0 || c == '%') {
|
||||
/* flush pending data on escape or end */
|
||||
escape = 1;
|
||||
lpref = 0;
|
||||
outstr = fmt;
|
||||
len = ofs - 1;
|
||||
flush_str:
|
||||
if (_fwrite(outstr, len, stream) != 0)
|
||||
break;
|
||||
|
||||
written += len;
|
||||
do_escape:
|
||||
if (c == 0)
|
||||
break;
|
||||
fmt += ofs;
|
||||
ofs = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* literal char, just queue it */
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int fprintf(FILE *stream, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vfprintf(stream, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vfprintf(stdout, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
void perror(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_STDIO_H */
|
||||
353
kernel/include/klibc/stdlib.h
Normal file
353
kernel/include/klibc/stdlib.h
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* stdlib function definitions for NOLIBC
|
||||
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_STDLIB_H
|
||||
#define _NOLIBC_STDLIB_H
|
||||
|
||||
#include "std.h"
|
||||
#include "arch.h"
|
||||
#include "types.h"
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
/* Buffer used to store int-to-ASCII conversions. Will only be implemented if
|
||||
* any of the related functions is implemented. The area is large enough to
|
||||
* store "18446744073709551615" or "-9223372036854775808" and the final zero.
|
||||
*/
|
||||
static __attribute__((unused)) char itoa_buffer[21];
|
||||
|
||||
/*
|
||||
* As much as possible, please keep functions alphabetically sorted.
|
||||
*/
|
||||
|
||||
/* must be exported, as it's used by libgcc for various divide functions */
|
||||
__attribute__((weak,unused,noreturn,section(".text.nolibc_abort")))
|
||||
void abort(void)
|
||||
{
|
||||
sys_kill(sys_getpid(), SIGABRT);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
long atol(const char *s)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
unsigned long d;
|
||||
int neg = 0;
|
||||
|
||||
if (*s == '-') {
|
||||
neg = 1;
|
||||
s++;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
d = (*s++) - '0';
|
||||
if (d > 9)
|
||||
break;
|
||||
ret *= 10;
|
||||
ret += d;
|
||||
}
|
||||
|
||||
return neg ? -ret : ret;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int atoi(const char *s)
|
||||
{
|
||||
return atol(s);
|
||||
}
|
||||
|
||||
/* Tries to find the environment variable named <name> in the environment array
|
||||
* pointed to by global variable "environ" which must be declared as a char **,
|
||||
* and must be terminated by a NULL (it is recommended to set this variable to
|
||||
* the "envp" argument of main()). If the requested environment variable exists
|
||||
* its value is returned otherwise NULL is returned.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
char *getenv(const char *name)
|
||||
{
|
||||
extern char **environ;
|
||||
int idx, i;
|
||||
|
||||
if (environ) {
|
||||
for (idx = 0; environ[idx]; idx++) {
|
||||
for (i = 0; name[i] && name[i] == environ[idx][i];)
|
||||
i++;
|
||||
if (!name[i] && environ[idx][i] == '=')
|
||||
return &environ[idx][i+1];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Converts the unsigned long integer <in> to its hex representation into
|
||||
* buffer <buffer>, which must be long enough to store the number and the
|
||||
* trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The
|
||||
* buffer is filled from the first byte, and the number of characters emitted
|
||||
* (not counting the trailing zero) is returned. The function is constructed
|
||||
* in a way to optimize the code size and avoid any divide that could add a
|
||||
* dependency on large external functions.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int utoh_r(unsigned long in, char *buffer)
|
||||
{
|
||||
signed char pos = (~0UL > 0xfffffffful) ? 60 : 28;
|
||||
int digits = 0;
|
||||
int dig;
|
||||
|
||||
do {
|
||||
dig = in >> pos;
|
||||
in -= (uint64_t)dig << pos;
|
||||
pos -= 4;
|
||||
if (dig || digits || pos < 0) {
|
||||
if (dig > 9)
|
||||
dig += 'a' - '0' - 10;
|
||||
buffer[digits++] = '0' + dig;
|
||||
}
|
||||
} while (pos >= 0);
|
||||
|
||||
buffer[digits] = 0;
|
||||
return digits;
|
||||
}
|
||||
|
||||
/* converts unsigned long <in> to an hex string using the static itoa_buffer
|
||||
* and returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *utoh(unsigned long in)
|
||||
{
|
||||
utoh_r(in, itoa_buffer);
|
||||
return itoa_buffer;
|
||||
}
|
||||
|
||||
/* Converts the unsigned long integer <in> to its string representation into
|
||||
* buffer <buffer>, which must be long enough to store the number and the
|
||||
* trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for
|
||||
* 4294967295 in 32-bit). The buffer is filled from the first byte, and the
|
||||
* number of characters emitted (not counting the trailing zero) is returned.
|
||||
* The function is constructed in a way to optimize the code size and avoid
|
||||
* any divide that could add a dependency on large external functions.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int utoa_r(unsigned long in, char *buffer)
|
||||
{
|
||||
unsigned long lim;
|
||||
int digits = 0;
|
||||
int pos = (~0UL > 0xfffffffful) ? 19 : 9;
|
||||
int dig;
|
||||
|
||||
do {
|
||||
for (dig = 0, lim = 1; dig < pos; dig++)
|
||||
lim *= 10;
|
||||
|
||||
if (digits || in >= lim || !pos) {
|
||||
for (dig = 0; in >= lim; dig++)
|
||||
in -= lim;
|
||||
buffer[digits++] = '0' + dig;
|
||||
}
|
||||
} while (pos--);
|
||||
|
||||
buffer[digits] = 0;
|
||||
return digits;
|
||||
}
|
||||
|
||||
/* Converts the signed long integer <in> to its string representation into
|
||||
* buffer <buffer>, which must be long enough to store the number and the
|
||||
* trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for
|
||||
* -2147483648 in 32-bit). The buffer is filled from the first byte, and the
|
||||
* number of characters emitted (not counting the trailing zero) is returned.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int itoa_r(long in, char *buffer)
|
||||
{
|
||||
char *ptr = buffer;
|
||||
int len = 0;
|
||||
|
||||
if (in < 0) {
|
||||
in = -in;
|
||||
*(ptr++) = '-';
|
||||
len++;
|
||||
}
|
||||
len += utoa_r(in, ptr);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* for historical compatibility, same as above but returns the pointer to the
|
||||
* buffer.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *ltoa_r(long in, char *buffer)
|
||||
{
|
||||
itoa_r(in, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* converts long integer <in> to a string using the static itoa_buffer and
|
||||
* returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *itoa(long in)
|
||||
{
|
||||
itoa_r(in, itoa_buffer);
|
||||
return itoa_buffer;
|
||||
}
|
||||
|
||||
/* converts long integer <in> to a string using the static itoa_buffer and
|
||||
* returns the pointer to that string. Same as above, for compatibility.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *ltoa(long in)
|
||||
{
|
||||
itoa_r(in, itoa_buffer);
|
||||
return itoa_buffer;
|
||||
}
|
||||
|
||||
/* converts unsigned long integer <in> to a string using the static itoa_buffer
|
||||
* and returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *utoa(unsigned long in)
|
||||
{
|
||||
utoa_r(in, itoa_buffer);
|
||||
return itoa_buffer;
|
||||
}
|
||||
|
||||
/* Converts the unsigned 64-bit integer <in> to its hex representation into
|
||||
* buffer <buffer>, which must be long enough to store the number and the
|
||||
* trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from
|
||||
* the first byte, and the number of characters emitted (not counting the
|
||||
* trailing zero) is returned. The function is constructed in a way to optimize
|
||||
* the code size and avoid any divide that could add a dependency on large
|
||||
* external functions.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int u64toh_r(uint64_t in, char *buffer)
|
||||
{
|
||||
signed char pos = 60;
|
||||
int digits = 0;
|
||||
int dig;
|
||||
|
||||
do {
|
||||
if (sizeof(long) >= 8) {
|
||||
dig = (in >> pos) & 0xF;
|
||||
} else {
|
||||
/* 32-bit platforms: avoid a 64-bit shift */
|
||||
uint32_t d = (pos >= 32) ? (in >> 32) : in;
|
||||
dig = (d >> (pos & 31)) & 0xF;
|
||||
}
|
||||
if (dig > 9)
|
||||
dig += 'a' - '0' - 10;
|
||||
pos -= 4;
|
||||
if (dig || digits || pos < 0)
|
||||
buffer[digits++] = '0' + dig;
|
||||
} while (pos >= 0);
|
||||
|
||||
buffer[digits] = 0;
|
||||
return digits;
|
||||
}
|
||||
|
||||
/* converts uint64_t <in> to an hex string using the static itoa_buffer and
|
||||
* returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *u64toh(uint64_t in)
|
||||
{
|
||||
u64toh_r(in, itoa_buffer);
|
||||
return itoa_buffer;
|
||||
}
|
||||
|
||||
/* Converts the unsigned 64-bit integer <in> to its string representation into
|
||||
* buffer <buffer>, which must be long enough to store the number and the
|
||||
* trailing zero (21 bytes for 18446744073709551615). The buffer is filled from
|
||||
* the first byte, and the number of characters emitted (not counting the
|
||||
* trailing zero) is returned. The function is constructed in a way to optimize
|
||||
* the code size and avoid any divide that could add a dependency on large
|
||||
* external functions.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int u64toa_r(uint64_t in, char *buffer)
|
||||
{
|
||||
unsigned long long lim;
|
||||
int digits = 0;
|
||||
int pos = 19; /* start with the highest possible digit */
|
||||
int dig;
|
||||
|
||||
do {
|
||||
for (dig = 0, lim = 1; dig < pos; dig++)
|
||||
lim *= 10;
|
||||
|
||||
if (digits || in >= lim || !pos) {
|
||||
for (dig = 0; in >= lim; dig++)
|
||||
in -= lim;
|
||||
buffer[digits++] = '0' + dig;
|
||||
}
|
||||
} while (pos--);
|
||||
|
||||
buffer[digits] = 0;
|
||||
return digits;
|
||||
}
|
||||
|
||||
/* Converts the signed 64-bit integer <in> to its string representation into
|
||||
* buffer <buffer>, which must be long enough to store the number and the
|
||||
* trailing zero (21 bytes for -9223372036854775808). The buffer is filled from
|
||||
* the first byte, and the number of characters emitted (not counting the
|
||||
* trailing zero) is returned.
|
||||
*/
|
||||
static __attribute__((unused))
|
||||
int i64toa_r(int64_t in, char *buffer)
|
||||
{
|
||||
char *ptr = buffer;
|
||||
int len = 0;
|
||||
|
||||
if (in < 0) {
|
||||
in = -in;
|
||||
*(ptr++) = '-';
|
||||
len++;
|
||||
}
|
||||
len += u64toa_r(in, ptr);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* converts int64_t <in> to a string using the static itoa_buffer and returns
|
||||
* the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *i64toa(int64_t in)
|
||||
{
|
||||
i64toa_r(in, itoa_buffer);
|
||||
return itoa_buffer;
|
||||
}
|
||||
|
||||
/* converts uint64_t <in> to a string using the static itoa_buffer and returns
|
||||
* the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
char *u64toa(uint64_t in)
|
||||
{
|
||||
u64toa_r(in, itoa_buffer);
|
||||
return itoa_buffer;
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_STDLIB_H */
|
||||
231
kernel/include/klibc/string.h
Normal file
231
kernel/include/klibc/string.h
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* string function definitions for NOLIBC
|
||||
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_STRING_H
|
||||
#define _NOLIBC_STRING_H
|
||||
|
||||
#include "std.h"
|
||||
|
||||
/*
|
||||
* As much as possible, please keep functions alphabetically sorted.
|
||||
*/
|
||||
|
||||
static __attribute__((unused))
|
||||
int memcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
size_t ofs = 0;
|
||||
char c1 = 0;
|
||||
|
||||
while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) {
|
||||
ofs++;
|
||||
}
|
||||
return c1;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
void *_nolibc_memcpy_up(void *dst, const void *src, size_t len)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
||||
while (pos < len) {
|
||||
((char *)dst)[pos] = ((const char *)src)[pos];
|
||||
pos++;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
void *_nolibc_memcpy_down(void *dst, const void *src, size_t len)
|
||||
{
|
||||
while (len) {
|
||||
len--;
|
||||
((char *)dst)[len] = ((const char *)src)[len];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* might be ignored by the compiler without -ffreestanding, then found as
|
||||
* missing.
|
||||
*/
|
||||
__attribute__((weak,unused,section(".text.nolibc_memmove")))
|
||||
void *memmove(void *dst, const void *src, size_t len)
|
||||
{
|
||||
size_t dir, pos;
|
||||
|
||||
pos = len;
|
||||
dir = -1;
|
||||
|
||||
if (dst < src) {
|
||||
pos = -1;
|
||||
dir = 1;
|
||||
}
|
||||
|
||||
while (len) {
|
||||
pos += dir;
|
||||
((char *)dst)[pos] = ((const char *)src)[pos];
|
||||
len--;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* must be exported, as it's used by libgcc on ARM */
|
||||
__attribute__((weak,unused,section(".text.nolibc_memcpy")))
|
||||
void *memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
return _nolibc_memcpy_up(dst, src, len);
|
||||
}
|
||||
|
||||
/* might be ignored by the compiler without -ffreestanding, then found as
|
||||
* missing.
|
||||
*/
|
||||
__attribute__((weak,unused,section(".text.nolibc_memset")))
|
||||
void *memset(void *dst, int b, size_t len)
|
||||
{
|
||||
char *p = dst;
|
||||
|
||||
while (len--)
|
||||
*(p++) = b;
|
||||
return dst;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
char *strchr(const char *s, int c)
|
||||
{
|
||||
while (*s) {
|
||||
if (*s == (char)c)
|
||||
return (char *)s;
|
||||
s++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
char *strcpy(char *dst, const char *src)
|
||||
{
|
||||
char *ret = dst;
|
||||
|
||||
while ((*dst++ = *src++));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* this function is only used with arguments that are not constants */
|
||||
static __attribute__((unused))
|
||||
size_t nolibc_strlen(const char *str)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
for (len = 0; str[len]; len++);
|
||||
return len;
|
||||
}
|
||||
|
||||
#define strlen(str) ({ \
|
||||
__builtin_constant_p((str)) ? \
|
||||
__builtin_strlen((str)) : \
|
||||
nolibc_strlen((str)); \
|
||||
})
|
||||
|
||||
static __attribute__((unused))
|
||||
size_t strlcat(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t len;
|
||||
char c;
|
||||
|
||||
for (len = 0; dst[len]; len++)
|
||||
;
|
||||
|
||||
for (;;) {
|
||||
c = *src;
|
||||
if (len < size)
|
||||
dst[len] = c;
|
||||
if (!c)
|
||||
break;
|
||||
len++;
|
||||
src++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
size_t strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t len;
|
||||
char c;
|
||||
|
||||
for (len = 0;;) {
|
||||
c = src[len];
|
||||
if (len < size)
|
||||
dst[len] = c;
|
||||
if (!c)
|
||||
break;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
char *strncat(char *dst, const char *src, size_t size)
|
||||
{
|
||||
char *orig = dst;
|
||||
|
||||
while (*dst)
|
||||
dst++;
|
||||
|
||||
while (size && (*dst = *src)) {
|
||||
src++;
|
||||
dst++;
|
||||
size--;
|
||||
}
|
||||
|
||||
*dst = 0;
|
||||
return orig;
|
||||
}
|
||||
|
||||
|
||||
static __attribute__((unused))
|
||||
char *strncpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
for (len = 0; len < size; len++)
|
||||
if ((dst[len] = *src))
|
||||
src++;
|
||||
return dst;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
char *strrchr(const char *s, int c)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
|
||||
while (*s) {
|
||||
if (*s == (char)c)
|
||||
ret = s;
|
||||
s++;
|
||||
}
|
||||
return (char *)ret;
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_STRING_H */
|
||||
1187
kernel/include/klibc/sys.h
Normal file
1187
kernel/include/klibc/sys.h
Normal file
File diff suppressed because it is too large
Load diff
47
kernel/include/klibc/time.h
Normal file
47
kernel/include/klibc/time.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* time function definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_TIME_H
|
||||
#define _NOLIBC_TIME_H
|
||||
|
||||
#include "std.h"
|
||||
#include "arch.h"
|
||||
#include "types.h"
|
||||
#include "sys.h"
|
||||
|
||||
static __attribute__((unused))
|
||||
time_t time(time_t *tptr)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
/* note, cannot fail here */
|
||||
sys_gettimeofday(&tv, NULL);
|
||||
|
||||
if (tptr)
|
||||
*tptr = tv.tv_sec;
|
||||
return tv.tv_sec;
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_TIME_H */
|
||||
203
kernel/include/klibc/types.h
Normal file
203
kernel/include/klibc/types.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Special types used by various syscalls for NOLIBC
|
||||
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_TYPES_H
|
||||
#define _NOLIBC_TYPES_H
|
||||
|
||||
#include "std.h"
|
||||
#include <linux/time.h>
|
||||
|
||||
|
||||
/* Only the generic macros and types may be defined here. The arch-specific
|
||||
* ones such as the O_RDONLY and related macros used by fcntl() and open(), or
|
||||
* the layout of sys_stat_struct must not be defined here.
|
||||
*/
|
||||
|
||||
/* stat flags (WARNING, octal here) */
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFCHR 0020000
|
||||
#define S_IFBLK 0060000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFIFO 0010000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFSOCK 0140000
|
||||
#define S_IFMT 0170000
|
||||
|
||||
#define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR)
|
||||
#define S_ISCHR(mode) (((mode) & S_IFCHR) == S_IFCHR)
|
||||
#define S_ISBLK(mode) (((mode) & S_IFBLK) == S_IFBLK)
|
||||
#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG)
|
||||
#define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO)
|
||||
#define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK)
|
||||
#define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK)
|
||||
|
||||
/* dirent types */
|
||||
#define DT_UNKNOWN 0x0
|
||||
#define DT_FIFO 0x1
|
||||
#define DT_CHR 0x2
|
||||
#define DT_DIR 0x4
|
||||
#define DT_BLK 0x6
|
||||
#define DT_REG 0x8
|
||||
#define DT_LNK 0xa
|
||||
#define DT_SOCK 0xc
|
||||
|
||||
/* commonly an fd_set represents 256 FDs */
|
||||
#ifndef FD_SETSIZE
|
||||
#define FD_SETSIZE 256
|
||||
#endif
|
||||
|
||||
/* PATH_MAX and MAXPATHLEN are often used and found with plenty of different
|
||||
* values.
|
||||
*/
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifndef MAXPATHLEN
|
||||
#define MAXPATHLEN (PATH_MAX)
|
||||
#endif
|
||||
|
||||
/* Special FD used by all the *at functions */
|
||||
#ifndef AT_FDCWD
|
||||
#define AT_FDCWD (-100)
|
||||
#endif
|
||||
|
||||
/* whence values for lseek() */
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
/* cmd for reboot() */
|
||||
#define LINUX_REBOOT_MAGIC1 0xfee1dead
|
||||
#define LINUX_REBOOT_MAGIC2 0x28121969
|
||||
#define LINUX_REBOOT_CMD_HALT 0xcdef0123
|
||||
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
|
||||
#define LINUX_REBOOT_CMD_RESTART 0x01234567
|
||||
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2
|
||||
|
||||
/* Macros used on waitpid()'s return status */
|
||||
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
|
||||
#define WIFEXITED(status) (((status) & 0x7f) == 0)
|
||||
|
||||
/* standard exit() codes */
|
||||
#define EXIT_SUCCESS 0
|
||||
#define EXIT_FAILURE 1
|
||||
|
||||
/* for select() */
|
||||
typedef struct {
|
||||
uint32_t fd32[(FD_SETSIZE + 31) / 32];
|
||||
} fd_set;
|
||||
|
||||
#define FD_CLR(fd, set) do { \
|
||||
fd_set *__set = (set); \
|
||||
int __fd = (fd); \
|
||||
if (__fd >= 0) \
|
||||
__set->fd32[__fd / 32] &= ~(1U << (__fd & 31)); \
|
||||
} while (0)
|
||||
|
||||
#define FD_SET(fd, set) do { \
|
||||
fd_set *__set = (set); \
|
||||
int __fd = (fd); \
|
||||
if (__fd >= 0) \
|
||||
__set->fd32[__fd / 32] |= 1U << (__fd & 31); \
|
||||
} while (0)
|
||||
|
||||
#define FD_ISSET(fd, set) ({ \
|
||||
fd_set *__set = (set); \
|
||||
int __fd = (fd); \
|
||||
int __r = 0; \
|
||||
if (__fd >= 0) \
|
||||
__r = !!(__set->fd32[__fd / 32] & 1U << (__fd & 31)); \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define FD_ZERO(set) do { \
|
||||
fd_set *__set = (set); \
|
||||
int __idx; \
|
||||
for (__idx = 0; __idx < (FD_SETSIZE+31) / 32; __idx ++) \
|
||||
__set->fd32[__idx] = 0; \
|
||||
} while (0)
|
||||
|
||||
/* for poll() */
|
||||
struct pollfd {
|
||||
int fd;
|
||||
short int events;
|
||||
short int revents;
|
||||
};
|
||||
|
||||
/* for getdents64() */
|
||||
struct linux_dirent64 {
|
||||
uint64_t d_ino;
|
||||
int64_t d_off;
|
||||
unsigned short d_reclen;
|
||||
unsigned char d_type;
|
||||
char d_name[];
|
||||
};
|
||||
|
||||
/* needed by wait4() */
|
||||
struct rusage {
|
||||
struct timeval ru_utime;
|
||||
struct timeval ru_stime;
|
||||
long ru_maxrss;
|
||||
long ru_ixrss;
|
||||
long ru_idrss;
|
||||
long ru_isrss;
|
||||
long ru_minflt;
|
||||
long ru_majflt;
|
||||
long ru_nswap;
|
||||
long ru_inblock;
|
||||
long ru_oublock;
|
||||
long ru_msgsnd;
|
||||
long ru_msgrcv;
|
||||
long ru_nsignals;
|
||||
long ru_nvcsw;
|
||||
long ru_nivcsw;
|
||||
};
|
||||
|
||||
/* The format of the struct as returned by the libc to the application, which
|
||||
* significantly differs from the format returned by the stat() syscall flavours.
|
||||
*/
|
||||
struct stat {
|
||||
dev_t st_dev; /* ID of device containing file */
|
||||
ino_t st_ino; /* inode number */
|
||||
mode_t st_mode; /* protection */
|
||||
nlink_t st_nlink; /* number of hard links */
|
||||
uid_t st_uid; /* user ID of owner */
|
||||
gid_t st_gid; /* group ID of owner */
|
||||
dev_t st_rdev; /* device ID (if special file) */
|
||||
off_t st_size; /* total size, in bytes */
|
||||
blksize_t st_blksize; /* blocksize for file system I/O */
|
||||
blkcnt_t st_blocks; /* number of 512B blocks allocated */
|
||||
time_t st_atime; /* time of last access */
|
||||
time_t st_mtime; /* time of last modification */
|
||||
time_t st_ctime; /* time of last status change */
|
||||
};
|
||||
|
||||
/* WARNING, it only deals with the 4096 first majors and 256 first minors */
|
||||
#define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
|
||||
#define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff))
|
||||
#define minor(dev) ((unsigned int)(((dev) & 0xff))
|
||||
|
||||
#endif /* _NOLIBC_TYPES_H */
|
||||
73
kernel/include/klibc/unistd.h
Normal file
73
kernel/include/klibc/unistd.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* unistd function definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_UNISTD_H
|
||||
#define _NOLIBC_UNISTD_H
|
||||
|
||||
#include "std.h"
|
||||
#include "arch.h"
|
||||
#include "types.h"
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
static __attribute__((unused))
|
||||
int msleep(unsigned int msecs)
|
||||
{
|
||||
struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 };
|
||||
|
||||
if (sys_select(0, 0, 0, 0, &my_timeval) < 0)
|
||||
return (my_timeval.tv_sec * 1000) +
|
||||
(my_timeval.tv_usec / 1000) +
|
||||
!!(my_timeval.tv_usec % 1000);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
struct timeval my_timeval = { seconds, 0 };
|
||||
|
||||
if (sys_select(0, 0, 0, 0, &my_timeval) < 0)
|
||||
return my_timeval.tv_sec + !!my_timeval.tv_usec;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int usleep(unsigned int usecs)
|
||||
{
|
||||
struct timeval my_timeval = { usecs / 1000000, usecs % 1000000 };
|
||||
|
||||
return sys_select(0, 0, 0, 0, &my_timeval);
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int tcsetpgrp(int fd, pid_t pid)
|
||||
{
|
||||
return ioctl(fd, TIOCSPGRP, &pid);
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_UNISTD_H */
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
size_t strlen(const char* str);
|
||||
|
||||
#endif // STRING_H
|
||||
754
kernel/include/limine.h
Normal file
754
kernel/include/limine.h
Normal file
|
|
@ -0,0 +1,754 @@
|
|||
/* BSD Zero Clause License */
|
||||
|
||||
/* Copyright (C) 2022-2025 Mintsuki and contributors.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIMINE_H
|
||||
#define LIMINE_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Misc */
|
||||
|
||||
#ifdef LIMINE_NO_POINTERS
|
||||
# define LIMINE_PTR(TYPE) uint64_t
|
||||
#else
|
||||
# define LIMINE_PTR(TYPE) TYPE
|
||||
#endif
|
||||
|
||||
#ifndef LIMINE_API_REVISION
|
||||
# define LIMINE_API_REVISION 0
|
||||
#endif
|
||||
|
||||
#if LIMINE_API_REVISION > 3
|
||||
# error "limine.h API revision unsupported"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define LIMINE_DEPRECATED __attribute__((__deprecated__))
|
||||
# define LIMINE_DEPRECATED_IGNORE_START \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
# define LIMINE_DEPRECATED_IGNORE_END \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
# define LIMINE_DEPRECATED
|
||||
# define LIMINE_DEPRECATED_IGNORE_START
|
||||
# define LIMINE_DEPRECATED_IGNORE_END
|
||||
#endif
|
||||
|
||||
#define LIMINE_REQUESTS_START_MARKER \
|
||||
uint64_t limine_requests_start_marker[4] = { 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, \
|
||||
0x785c6ed015d3e316, 0x181e920a7852b9d9 };
|
||||
#define LIMINE_REQUESTS_END_MARKER \
|
||||
uint64_t limine_requests_end_marker[2] = { 0xadc0e0531bb10d03, 0x9572709f31764c62 };
|
||||
|
||||
#define LIMINE_REQUESTS_DELIMITER LIMINE_REQUESTS_END_MARKER
|
||||
|
||||
#define LIMINE_BASE_REVISION(N) \
|
||||
uint64_t limine_base_revision[3] = { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) };
|
||||
|
||||
#define LIMINE_BASE_REVISION_SUPPORTED (limine_base_revision[2] == 0)
|
||||
|
||||
#define LIMINE_LOADED_BASE_REV_VALID (limine_base_revision[1] != 0x6a7b384944536bdc)
|
||||
#define LIMINE_LOADED_BASE_REVISION (limine_base_revision[1])
|
||||
|
||||
#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b
|
||||
|
||||
struct limine_uuid {
|
||||
uint32_t a;
|
||||
uint16_t b;
|
||||
uint16_t c;
|
||||
uint8_t d[8];
|
||||
};
|
||||
|
||||
#define LIMINE_MEDIA_TYPE_GENERIC 0
|
||||
#define LIMINE_MEDIA_TYPE_OPTICAL 1
|
||||
#define LIMINE_MEDIA_TYPE_TFTP 2
|
||||
|
||||
struct limine_file {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) address;
|
||||
uint64_t size;
|
||||
LIMINE_PTR(char *) path;
|
||||
#if LIMINE_API_REVISION >= 3
|
||||
LIMINE_PTR(char *) string;
|
||||
#else
|
||||
LIMINE_PTR(char *) cmdline;
|
||||
#endif
|
||||
uint32_t media_type;
|
||||
uint32_t unused;
|
||||
uint32_t tftp_ip;
|
||||
uint32_t tftp_port;
|
||||
uint32_t partition_index;
|
||||
uint32_t mbr_disk_id;
|
||||
struct limine_uuid gpt_disk_uuid;
|
||||
struct limine_uuid gpt_part_uuid;
|
||||
struct limine_uuid part_uuid;
|
||||
};
|
||||
|
||||
/* Boot info */
|
||||
|
||||
#define LIMINE_BOOTLOADER_INFO_REQUEST { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 }
|
||||
|
||||
struct limine_bootloader_info_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(char *) name;
|
||||
LIMINE_PTR(char *) version;
|
||||
};
|
||||
|
||||
struct limine_bootloader_info_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_bootloader_info_response *) response;
|
||||
};
|
||||
|
||||
/* Executable command line */
|
||||
|
||||
#define LIMINE_EXECUTABLE_CMDLINE_REQUEST { LIMINE_COMMON_MAGIC, 0x4b161536e598651e, 0xb390ad4a2f1f303a }
|
||||
|
||||
struct limine_executable_cmdline_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(char *) cmdline;
|
||||
};
|
||||
|
||||
struct limine_executable_cmdline_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_executable_cmdline_response *) response;
|
||||
};
|
||||
|
||||
/* Firmware type */
|
||||
|
||||
#define LIMINE_FIRMWARE_TYPE_REQUEST { LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3 }
|
||||
|
||||
#define LIMINE_FIRMWARE_TYPE_X86BIOS 0
|
||||
#define LIMINE_FIRMWARE_TYPE_UEFI32 1
|
||||
#define LIMINE_FIRMWARE_TYPE_UEFI64 2
|
||||
#define LIMINE_FIRMWARE_TYPE_SBI 3
|
||||
|
||||
struct limine_firmware_type_response {
|
||||
uint64_t revision;
|
||||
uint64_t firmware_type;
|
||||
};
|
||||
|
||||
struct limine_firmware_type_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_firmware_type_response *) response;
|
||||
};
|
||||
|
||||
/* Stack size */
|
||||
|
||||
#define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d }
|
||||
|
||||
struct limine_stack_size_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_stack_size_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_stack_size_response *) response;
|
||||
uint64_t stack_size;
|
||||
};
|
||||
|
||||
/* HHDM */
|
||||
|
||||
#define LIMINE_HHDM_REQUEST { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b }
|
||||
|
||||
struct limine_hhdm_response {
|
||||
uint64_t revision;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct limine_hhdm_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_hhdm_response *) response;
|
||||
};
|
||||
|
||||
/* Framebuffer */
|
||||
|
||||
#define LIMINE_FRAMEBUFFER_REQUEST { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b }
|
||||
|
||||
#define LIMINE_FRAMEBUFFER_RGB 1
|
||||
|
||||
struct limine_video_mode {
|
||||
uint64_t pitch;
|
||||
uint64_t width;
|
||||
uint64_t height;
|
||||
uint16_t bpp;
|
||||
uint8_t memory_model;
|
||||
uint8_t red_mask_size;
|
||||
uint8_t red_mask_shift;
|
||||
uint8_t green_mask_size;
|
||||
uint8_t green_mask_shift;
|
||||
uint8_t blue_mask_size;
|
||||
uint8_t blue_mask_shift;
|
||||
};
|
||||
|
||||
struct limine_framebuffer {
|
||||
LIMINE_PTR(void *) address;
|
||||
uint64_t width;
|
||||
uint64_t height;
|
||||
uint64_t pitch;
|
||||
uint16_t bpp;
|
||||
uint8_t memory_model;
|
||||
uint8_t red_mask_size;
|
||||
uint8_t red_mask_shift;
|
||||
uint8_t green_mask_size;
|
||||
uint8_t green_mask_shift;
|
||||
uint8_t blue_mask_size;
|
||||
uint8_t blue_mask_shift;
|
||||
uint8_t unused[7];
|
||||
uint64_t edid_size;
|
||||
LIMINE_PTR(void *) edid;
|
||||
/* Response revision 1 */
|
||||
uint64_t mode_count;
|
||||
LIMINE_PTR(struct limine_video_mode **) modes;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_response {
|
||||
uint64_t revision;
|
||||
uint64_t framebuffer_count;
|
||||
LIMINE_PTR(struct limine_framebuffer **) framebuffers;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_framebuffer_response *) response;
|
||||
};
|
||||
|
||||
/* Terminal */
|
||||
|
||||
#define LIMINE_TERMINAL_REQUEST { LIMINE_COMMON_MAGIC, 0xc8ac59310c2b0844, 0xa68d0c7265d38878 }
|
||||
|
||||
#define LIMINE_TERMINAL_CB_DEC 10
|
||||
#define LIMINE_TERMINAL_CB_BELL 20
|
||||
#define LIMINE_TERMINAL_CB_PRIVATE_ID 30
|
||||
#define LIMINE_TERMINAL_CB_STATUS_REPORT 40
|
||||
#define LIMINE_TERMINAL_CB_POS_REPORT 50
|
||||
#define LIMINE_TERMINAL_CB_KBD_LEDS 60
|
||||
#define LIMINE_TERMINAL_CB_MODE 70
|
||||
#define LIMINE_TERMINAL_CB_LINUX 80
|
||||
|
||||
#define LIMINE_TERMINAL_CTX_SIZE ((uint64_t)(-1))
|
||||
#define LIMINE_TERMINAL_CTX_SAVE ((uint64_t)(-2))
|
||||
#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3))
|
||||
#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4))
|
||||
|
||||
/* Response revision 1 */
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_GET ((uint64_t)(-10))
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_SET ((uint64_t)(-11))
|
||||
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_OCRNL (1 << 0)
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_OFDEL (1 << 1)
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_OFILL (1 << 2)
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_OLCUC (1 << 3)
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_ONLCR (1 << 4)
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_ONLRET (1 << 5)
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_ONOCR (1 << 6)
|
||||
#define LIMINE_TERMINAL_OOB_OUTPUT_OPOST (1 << 7)
|
||||
|
||||
LIMINE_DEPRECATED_IGNORE_START
|
||||
|
||||
struct LIMINE_DEPRECATED limine_terminal;
|
||||
|
||||
typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t);
|
||||
typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
|
||||
struct LIMINE_DEPRECATED limine_terminal {
|
||||
uint64_t columns;
|
||||
uint64_t rows;
|
||||
LIMINE_PTR(struct limine_framebuffer *) framebuffer;
|
||||
};
|
||||
|
||||
struct LIMINE_DEPRECATED limine_terminal_response {
|
||||
uint64_t revision;
|
||||
uint64_t terminal_count;
|
||||
LIMINE_PTR(struct limine_terminal **) terminals;
|
||||
LIMINE_PTR(limine_terminal_write) write;
|
||||
};
|
||||
|
||||
struct LIMINE_DEPRECATED limine_terminal_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_terminal_response *) response;
|
||||
LIMINE_PTR(limine_terminal_callback) callback;
|
||||
};
|
||||
|
||||
LIMINE_DEPRECATED_IGNORE_END
|
||||
|
||||
/* Paging mode */
|
||||
|
||||
#define LIMINE_PAGING_MODE_REQUEST { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a }
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
#define LIMINE_PAGING_MODE_X86_64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_X86_64_5LVL 1
|
||||
#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_X86_64_4LVL
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL
|
||||
#elif defined (__aarch64__)
|
||||
#define LIMINE_PAGING_MODE_AARCH64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_AARCH64_5LVL 1
|
||||
#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_AARCH64_4LVL
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL
|
||||
#elif defined (__riscv) && (__riscv_xlen == 64)
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV39 0
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV48 1
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV57 2
|
||||
#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_RISCV_SV39
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48
|
||||
#elif defined (__loongarch__) && (__loongarch_grlen == 64)
|
||||
#define LIMINE_PAGING_MODE_LOONGARCH64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_LOONGARCH64_4LVL
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_LOONGARCH64_4LVL
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
struct limine_paging_mode_response {
|
||||
uint64_t revision;
|
||||
uint64_t mode;
|
||||
};
|
||||
|
||||
struct limine_paging_mode_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_paging_mode_response *) response;
|
||||
uint64_t mode;
|
||||
uint64_t max_mode;
|
||||
uint64_t min_mode;
|
||||
};
|
||||
|
||||
/* 5-level paging */
|
||||
|
||||
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
|
||||
|
||||
LIMINE_DEPRECATED_IGNORE_START
|
||||
|
||||
struct LIMINE_DEPRECATED limine_5_level_paging_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct LIMINE_DEPRECATED limine_5_level_paging_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_5_level_paging_response *) response;
|
||||
};
|
||||
|
||||
LIMINE_DEPRECATED_IGNORE_END
|
||||
|
||||
/* MP */
|
||||
|
||||
#if LIMINE_API_REVISION >= 1
|
||||
# define LIMINE_MP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
|
||||
# define LIMINE_MP(TEXT) limine_mp_##TEXT
|
||||
#else
|
||||
# define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
|
||||
# define LIMINE_MP(TEXT) limine_smp_##TEXT
|
||||
#endif
|
||||
|
||||
struct LIMINE_MP(info);
|
||||
|
||||
typedef void (*limine_goto_address)(struct LIMINE_MP(info) *);
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
|
||||
#if LIMINE_API_REVISION >= 1
|
||||
# define LIMINE_MP_X2APIC (1 << 0)
|
||||
#else
|
||||
# define LIMINE_SMP_X2APIC (1 << 0)
|
||||
#endif
|
||||
|
||||
struct LIMINE_MP(info) {
|
||||
uint32_t processor_id;
|
||||
uint32_t lapic_id;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct LIMINE_MP(response) {
|
||||
uint64_t revision;
|
||||
uint32_t flags;
|
||||
uint32_t bsp_lapic_id;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct LIMINE_MP(info) **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__aarch64__)
|
||||
|
||||
struct LIMINE_MP(info) {
|
||||
uint32_t processor_id;
|
||||
uint32_t reserved1;
|
||||
uint64_t mpidr;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct LIMINE_MP(response) {
|
||||
uint64_t revision;
|
||||
uint64_t flags;
|
||||
uint64_t bsp_mpidr;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct LIMINE_MP(info) **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__riscv) && (__riscv_xlen == 64)
|
||||
|
||||
struct LIMINE_MP(info) {
|
||||
uint64_t processor_id;
|
||||
uint64_t hartid;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct LIMINE_MP(response) {
|
||||
uint64_t revision;
|
||||
uint64_t flags;
|
||||
uint64_t bsp_hartid;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct LIMINE_MP(info) **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__loongarch__) && (__loongarch_grlen == 64)
|
||||
|
||||
struct LIMINE_MP(info) {
|
||||
uint64_t reserved;
|
||||
};
|
||||
|
||||
struct LIMINE_MP(response) {
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct LIMINE_MP(info) **) cpus;
|
||||
};
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
struct LIMINE_MP(request) {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct LIMINE_MP(response) *) response;
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
/* Memory map */
|
||||
|
||||
#define LIMINE_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 }
|
||||
|
||||
#define LIMINE_MEMMAP_USABLE 0
|
||||
#define LIMINE_MEMMAP_RESERVED 1
|
||||
#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2
|
||||
#define LIMINE_MEMMAP_ACPI_NVS 3
|
||||
#define LIMINE_MEMMAP_BAD_MEMORY 4
|
||||
#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
# define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6
|
||||
#else
|
||||
# define LIMINE_MEMMAP_KERNEL_AND_MODULES 6
|
||||
#endif
|
||||
#define LIMINE_MEMMAP_FRAMEBUFFER 7
|
||||
|
||||
struct limine_memmap_entry {
|
||||
uint64_t base;
|
||||
uint64_t length;
|
||||
uint64_t type;
|
||||
};
|
||||
|
||||
struct limine_memmap_response {
|
||||
uint64_t revision;
|
||||
uint64_t entry_count;
|
||||
LIMINE_PTR(struct limine_memmap_entry **) entries;
|
||||
};
|
||||
|
||||
struct limine_memmap_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_memmap_response *) response;
|
||||
};
|
||||
|
||||
/* Entry point */
|
||||
|
||||
#define LIMINE_ENTRY_POINT_REQUEST { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a }
|
||||
|
||||
typedef void (*limine_entry_point)(void);
|
||||
|
||||
struct limine_entry_point_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_entry_point_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_entry_point_response *) response;
|
||||
LIMINE_PTR(limine_entry_point) entry;
|
||||
};
|
||||
|
||||
/* Executable File */
|
||||
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
# define LIMINE_EXECUTABLE_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 }
|
||||
#else
|
||||
# define LIMINE_KERNEL_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 }
|
||||
#endif
|
||||
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
struct limine_executable_file_response {
|
||||
#else
|
||||
struct limine_kernel_file_response {
|
||||
#endif
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
LIMINE_PTR(struct limine_file *) executable_file;
|
||||
#else
|
||||
LIMINE_PTR(struct limine_file *) kernel_file;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
struct limine_executable_file_request {
|
||||
#else
|
||||
struct limine_kernel_file_request {
|
||||
#endif
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
LIMINE_PTR(struct limine_executable_file_response *) response;
|
||||
#else
|
||||
LIMINE_PTR(struct limine_kernel_file_response *) response;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Module */
|
||||
|
||||
#define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee }
|
||||
|
||||
#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0)
|
||||
#define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1)
|
||||
|
||||
struct limine_internal_module {
|
||||
LIMINE_PTR(const char *) path;
|
||||
#if LIMINE_API_REVISION >= 3
|
||||
LIMINE_PTR(const char *) string;
|
||||
#else
|
||||
LIMINE_PTR(const char *) cmdline;
|
||||
#endif
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
struct limine_module_response {
|
||||
uint64_t revision;
|
||||
uint64_t module_count;
|
||||
LIMINE_PTR(struct limine_file **) modules;
|
||||
};
|
||||
|
||||
struct limine_module_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_module_response *) response;
|
||||
|
||||
/* Request revision 1 */
|
||||
uint64_t internal_module_count;
|
||||
LIMINE_PTR(struct limine_internal_module **) internal_modules;
|
||||
};
|
||||
|
||||
/* RSDP */
|
||||
|
||||
#define LIMINE_RSDP_REQUEST { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c }
|
||||
|
||||
struct limine_rsdp_response {
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 1
|
||||
uint64_t address;
|
||||
#else
|
||||
LIMINE_PTR(void *) address;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct limine_rsdp_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_rsdp_response *) response;
|
||||
};
|
||||
|
||||
/* SMBIOS */
|
||||
|
||||
#define LIMINE_SMBIOS_REQUEST { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee }
|
||||
|
||||
struct limine_smbios_response {
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 1
|
||||
uint64_t entry_32;
|
||||
uint64_t entry_64;
|
||||
#else
|
||||
LIMINE_PTR(void *) entry_32;
|
||||
LIMINE_PTR(void *) entry_64;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct limine_smbios_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_smbios_response *) response;
|
||||
};
|
||||
|
||||
/* EFI system table */
|
||||
|
||||
#define LIMINE_EFI_SYSTEM_TABLE_REQUEST { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc }
|
||||
|
||||
struct limine_efi_system_table_response {
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 1
|
||||
uint64_t address;
|
||||
#else
|
||||
LIMINE_PTR(void *) address;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct limine_efi_system_table_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_efi_system_table_response *) response;
|
||||
};
|
||||
|
||||
/* EFI memory map */
|
||||
|
||||
#define LIMINE_EFI_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x7df62a431d6872d5, 0xa4fcdfb3e57306c8 }
|
||||
|
||||
struct limine_efi_memmap_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) memmap;
|
||||
uint64_t memmap_size;
|
||||
uint64_t desc_size;
|
||||
uint64_t desc_version;
|
||||
};
|
||||
|
||||
struct limine_efi_memmap_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_efi_memmap_response *) response;
|
||||
};
|
||||
|
||||
/* Date at boot */
|
||||
|
||||
#if LIMINE_API_REVISION >= 3
|
||||
# define LIMINE_DATE_AT_BOOT_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 }
|
||||
#else
|
||||
# define LIMINE_BOOT_TIME_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 }
|
||||
#endif
|
||||
|
||||
#if LIMINE_API_REVISION >= 3
|
||||
struct limine_date_at_boot_response {
|
||||
#else
|
||||
struct limine_boot_time_response {
|
||||
#endif
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 3
|
||||
int64_t timestamp;
|
||||
#else
|
||||
int64_t boot_time;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if LIMINE_API_REVISION >= 3
|
||||
struct limine_date_at_boot_request {
|
||||
#else
|
||||
struct limine_boot_time_request {
|
||||
#endif
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 3
|
||||
LIMINE_PTR(struct limine_date_at_boot_response *) response;
|
||||
#else
|
||||
LIMINE_PTR(struct limine_boot_time_response *) response;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Executable address */
|
||||
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
# define LIMINE_EXECUTABLE_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 }
|
||||
#else
|
||||
# define LIMINE_KERNEL_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 }
|
||||
#endif
|
||||
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
struct limine_executable_address_response {
|
||||
#else
|
||||
struct limine_kernel_address_response {
|
||||
#endif
|
||||
uint64_t revision;
|
||||
uint64_t physical_base;
|
||||
uint64_t virtual_base;
|
||||
};
|
||||
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
struct limine_executable_address_request {
|
||||
#else
|
||||
struct limine_kernel_address_request {
|
||||
#endif
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
#if LIMINE_API_REVISION >= 2
|
||||
LIMINE_PTR(struct limine_executable_address_response *) response;
|
||||
#else
|
||||
LIMINE_PTR(struct limine_kernel_address_response *) response;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Device Tree Blob */
|
||||
|
||||
#define LIMINE_DTB_REQUEST { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 }
|
||||
|
||||
struct limine_dtb_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) dtb_ptr;
|
||||
};
|
||||
|
||||
struct limine_dtb_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_dtb_response *) response;
|
||||
};
|
||||
|
||||
/* RISC-V Boot Hart ID */
|
||||
|
||||
#define LIMINE_RISCV_BSP_HARTID_REQUEST { LIMINE_COMMON_MAGIC, 0x1369359f025525f9, 0x2ff2a56178391bb6 }
|
||||
|
||||
struct limine_riscv_bsp_hartid_response {
|
||||
uint64_t revision;
|
||||
uint64_t bsp_hartid;
|
||||
};
|
||||
|
||||
struct limine_riscv_bsp_hartid_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,10 +1,41 @@
|
|||
#include <drivers/video/vga.h>
|
||||
#include <string.h>
|
||||
#include <klibc/string.h>
|
||||
/* #include <drivers/video/vga.h> */
|
||||
#include <stddef.h>
|
||||
#include <bootloader.h>
|
||||
|
||||
static void hcf(void) {
|
||||
for (;;) {
|
||||
__asm__("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kernel_main(void)
|
||||
{
|
||||
/* Make sure the bootloader understands our base revision */
|
||||
if (LIMINE_BASE_REVISION_SUPPORTED == 0) hcf();
|
||||
|
||||
/* ensure a framebuffer */
|
||||
if (framebuffer_request.response == NULL
|
||||
|| framebuffer_request.response->framebuffer_count < 1) hcf();
|
||||
|
||||
/* fetch the first framebuffer */
|
||||
struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0];
|
||||
|
||||
/* assume framebuffer model is RGB w/32-bit pixels */
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
volatile uint32_t *fb_ptr = framebuffer->address;
|
||||
fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff;
|
||||
}
|
||||
|
||||
/* need to get an actual framebuffer driver working before we can use vga */
|
||||
|
||||
/*
|
||||
term_init();
|
||||
|
||||
term_writestr("Hello World!\n");
|
||||
term_writestr("Hello World!");
|
||||
*/
|
||||
|
||||
/* done so now hang */
|
||||
hcf();
|
||||
}
|
||||
|
|
|
|||
BIN
kernel/init/kernel.o
Normal file
BIN
kernel/init/kernel.o
Normal file
Binary file not shown.
|
|
@ -1,11 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
size_t
|
||||
strlen(const char* str)
|
||||
{
|
||||
size_t len = 0;
|
||||
while (str[len]) len++;
|
||||
return len;
|
||||
}
|
||||
68
kernel/linker.ld
Normal file
68
kernel/linker.ld
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* Tell the linker that we want an x86_64 ELF64 output file */
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
/* We want the symbol kmain to be our entry point */
|
||||
ENTRY(kernel_main)
|
||||
|
||||
/* Define the program headers we want so the bootloader gives us the right */
|
||||
/* MMU permissions; this also allows us to exert more control over the linking */
|
||||
/* process. */
|
||||
PHDRS
|
||||
{
|
||||
limine_requests PT_LOAD;
|
||||
text PT_LOAD;
|
||||
rodata PT_LOAD;
|
||||
data PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
|
||||
/* and because that is what the Limine spec mandates. */
|
||||
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
|
||||
/* that is the beginning of the region. */
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
KEEP(*(.limine_requests_end))
|
||||
} :limine_requests
|
||||
|
||||
/* Move to the next memory page for .text */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
/* Move to the next memory page for .rodata */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
/* Move to the next memory page for .data */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
|
||||
/* unnecessary zeros will be written to the binary. */
|
||||
/* If you need, for example, .init_array and .fini_array, those should be placed */
|
||||
/* above this. */
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame*)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue