Compare commits

..

6 commits
master ... dev

Author SHA1 Message Date
Imbus
3f74e55322 Alias 2025-09-01 21:51:24 +02:00
Imbus
13b91e7aae Bad makefile 2025-09-01 21:51:14 +02:00
Imbus
2830ad60e1 Toolchain ignore 2025-09-01 21:50:46 +02:00
Imbus
ae356930d8 Renames 2025-09-01 21:50:22 +02:00
Imbus
ea016307cf Moves 2025-09-01 21:50:15 +02:00
Imbus
d078e7fb93 Moves 2025-09-01 21:50:05 +02:00
50 changed files with 856 additions and 1797 deletions

View file

@ -1,4 +0,0 @@
**/mini-printf.c
**/mini-printf.h
**/monocypher.c
**/monocypher.h

153
Makefile
View file

@ -1,19 +1,6 @@
# See: https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases
# See: https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases
GCC_VER := 14.2.0-3
QEMU_VER := 8.2.6-1
SYS_TOOLPREFIX ?= riscv64-linux-gnu
GCC_PATH := toolchain/gcc/bin
LOCAL_TOOLPREFIX := $(GCC_PATH)/riscv-none-elf
# TODO: Some wildcard condition to detect prefix
TOOLPREFIX := $(LOCAL_TOOLPREFIX)
# TOOLPREFIX := $(SYS_TOOLPREFIX)
QEMU_PATH := toolchain/qemu/bin
QEMU = $(QEMU_PATH)/qemu-system-riscv64
# TOOLPREFIX = riscv64-linux-gnu
# TOOLPREFIX = toolchain/xpack-riscv-none-elf-gcc-14.2.0-3/bin/riscv-none-elf
TOOLPREFIX = toolchain/gcc/bin/riscv-none-elf
CC = $(TOOLPREFIX)-gcc
AS = $(TOOLPREFIX)-as
@ -23,18 +10,14 @@ OBJDUMP = $(TOOLPREFIX)-objdump
ASFLAGS = -march=rv64gc -mabi=lp64
LDFLAGS = -Tkern/kernel.ld
LDFLAGS = -Tkernel.ld
LDFLAGS += -m elf64lriscv
CFLAGS = -Wall -Werror -O
CFLAGS += -Wno-unused-result
CFLAGS += -mcmodel=medany
CFLAGS += -march=rv64gc -mabi=lp64
CFLAGS += -ffreestanding
CFLAGS += -fno-common
CFLAGS += -nostdlib
CFLAGS += -mno-relax
CFLAGS += -std=gnu99
CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support
CFLAGS += -MD # Generate header dependency files (.d)
@ -42,113 +25,93 @@ CFLAGS += -fno-pie -no-pie # Fixed address linking
CFLAGS += -ggdb -gdwarf-2 # GDB debug info
CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB
KCFLAGS += $(CGFLAGS)
KCFLAGS += -DNEPTUNE_KERNEL
KCFLAGS += -Ikern
KCFLAGS += -Ikern/libkern
KCFLAGS += -I.
CFLAGS += -I.
CFLAGS += -I./kern
CFLAGS += -I./kern/libkern
CFLAGS += -Ilib
all: kern/kernel.elf
build: all
all: kernel.elf
quickstart:
make get_toolchain && bear -- make -j$(nproc) && make qemu
main: main.o
KERNEL_OBJ := \
kern/entry.o \
kern/start.o \
kern/libkern/freelist.o \
kern/libkern/string.o \
kern/libkern/proc.o \
kern/libkern/uart.o \
kern/libkern/panic.o \
kern/libkern/memory.o \
kern/libkern/spinlock.o \
kern/libkern/mini-printf.o \
kern/libkern/stdio.o \
kern/libkern/buddy.o \
kern/libkern/badrand.o
kern/kernel.elf: $(KERNEL_OBJ)
kernel.elf: entry.o start.o kern/libkern/string.o kern/libkern/proc.o kern/libkern/uart.o kern/libkern/panic.o kern/kalloc.o kern/libkern/memory.o kern/ispinlock.o kern/libkern/spinlock.o kern/libkern/string.o kern/libkern/mini-printf.o
@echo LD $@
@$(LD) $(LDFLAGS) -o $@ $^
%.o: %.c
@echo CC $@
@$(CC) $(CFLAGS) -nostdinc -I. -c $< -o $@
@$(CC) $(KCFLAGS) -nostdinc -I. -c $< -o $@
%.o: %.S
@echo AS $@
@$(AS) $(ASFLAGS) -o $@ $<
qemu: kern/kernel.elf
qemu: kernel.elf
@echo QEMU $<
@$(QEMU) -machine virt -bios none -nographic -m 128M -smp 4 -kernel $<
@qemu-system-riscv64 -machine virt -bios none -nographic -m 128M -smp 4 -kernel kernel.elf
clean:
find . -type f -name '*.[od(elf)]' -exec rm -f {} +
rm -f *.o *.elf *.d lib/*.o lib/*.d
fd -e o -x rm # TODO: Should only depend on posix
format:
find kern -type f -name '*.[ch]' -exec clang-format -i {} \;
-include *.d
help:
@echo "Available targets:"
@echo " quickstart Runs get_toolchain, build and qemu in sequence. Generates compile-commands.json. RUN ONLY ONCE"
@echo " build - Build the project"
@echo " qemu - Run the kernel in qemu"
@echo " clean Remove build artifacts (*.o, *.d, *.elf)"
@echo " distclean Same as clean, but also purges toolchain"
@echo " format Run clang-format over all kernel sources"
@echo " get_toolchain Fetchest the toolchain and extracts it into ./toolchain"
@echo " info Get some general info on toolchain versions and flags"
# --------------------------------------------------------------------
# Toolchain configuration
# --------------------------------------------------------------------
TOOLCHAIN_DIR := toolchain
QEMU_TARBALL := xpack-qemu-riscv-$(QEMU_VER)-linux-x64.tar.gz
GCC_TARBALL := xpack-riscv-none-elf-gcc-$(GCC_VER)-linux-x64.tar.gz
# Versions
QEMU_VER := 8.2.6-1
GCC_VER := 14.2.0-3
# Filenames
QEMU_TARBALL := xpack-qemu-riscv-$(QEMU_VER)-linux-arm.tar.gz
GCC_TARBALL := xpack-riscv-none-elf-gcc-$(GCC_VER)-linux-arm.tar.gz
# URLs
QEMU_URL := https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases/download/v$(QEMU_VER)/$(QEMU_TARBALL)
GCC_URL := https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v$(GCC_VER)/$(GCC_TARBALL)
QEMU_TARPATH := toolchain/$(QEMU_TARBALL)
GCC_TARPATH := toolchain/$(GCC_TARBALL)
# Paths
QEMU_TARPATH := toolchain/xpack-qemu-riscv-8.2.6-1-linux-arm.tar.gz
GCC_TARPATH := toolchain/xpack-riscv-none-elf-gcc-14.2.0-3-linux-arm.tar.gz
# Extracted directories
QEMU_DIR := $(TOOLCHAIN_DIR)/xpack-qemu-riscv-$(QEMU_VER)
GCC_DIR := $(TOOLCHAIN_DIR)/xpack-riscv-none-elf-gcc-$(GCC_VER)
# Symlink targets
QEMU_SYM_DIR := xpack-qemu-riscv-$(QEMU_VER)
GCC_SYM_DIR := xpack-riscv-none-elf-gcc-$(GCC_VER)
$(TOOLCHAIN_DIR):
@mkdir -p $@
# Final symlink/alias
GCC_ALIAS := gcc
QEMU_ALIAS := qemu
$(QEMU_TARPATH): $(TOOLCHAIN_DIR)
@echo "Fetching qemu-riscv-xpack: v$(QEMU_VER)"
@curl -# -L -o $@ $(QEMU_URL)
QEMU_TARPATH:
curl -# -L -o $@ $(QEMU_URL)
$(GCC_TARPATH): $(TOOLCHAIN_DIR)
@echo "Fetching riscv-none-elf-gcc-xpack: v$(GCC_VER)"
@curl -# -L -o $@ $(GCC_URL)
GCC_TARPATH:
curl -# -L -o $@ $(GCC_URL)
get_toolchain: $(TOOLCHAIN_DIR) $(GCC_TARPATH) $(QEMU_TARPATH)
@echo "Unpacking qemu..."
@cd toolchain && tar xf $(QEMU_TARBALL)
@echo "Unpacking gcc..."
@cd toolchain && tar xf $(GCC_TARBALL)
@cd $(TOOLCHAIN_DIR) && ln -sfn $(QEMU_SYM_DIR) qemu
@cd $(TOOLCHAIN_DIR) && ln -sfn $(GCC_SYM_DIR) gcc
@echo "Toolchain in place, ready to make!"
extractions:
cd toolchain && tar xf $(QEMU_TARBALL)
cd toolchain && tar xf $(GCC_TARBALL)
toolchain: $(QEMU_TARPATH) $(GCC_TARPATH)
mkdir -p toolchain
cd toolchain && tar xf $(QEMU_TARBALL)
cd toolchain && tar xf $(GCC_TARBALL)
cd $(TOOLCHAIN_DIR) && ln -sfn $(QEMU_SYM_DIR) $(QEMU_ALIAS)
cd $(TOOLCHAIN_DIR) && ln -sfn $(GCC_SYM_DIR) $(GCC_ALIAS)
distclean: clean
rm -rf $(TOOLCHAIN_DIR)
info:
@echo "Using qemu v$(QEMU_VER): $(QEMU)"
@echo "Using toolchain gcc v$(GCC_VER): $(TOOLPREFIX)"
@echo "CFLAGS:"
@for flag in $(CFLAGS); do \
printf " %s\n" "$$flag"; \
done
@echo "LDFLAGS:"
@for flag in $(LDFLAGS); do \
printf " %s\n" "$$flag"; \
done
-include *.d
.PHONY: all qemu info quickstart help build
.PHONY: all toolchain

View file

@ -5,56 +5,7 @@ Inspired by xv6
For a quick reference on RISC-V assembly:
- https://risc-v.guru/instructions/
Some low-level string format routines borrowed from [mini-printf](https://github.com/mludvig/mini-printf)
### Directory outline
The planned directory outline is as follows:
```
root
├── kern # General kernel sources
│ ├── libkern # Kernel specific library routines
│ ├── memory # Memory related code (kalloc, buddy and friends)
│ └── arch # Architecture specific functionality
├── libc # Userspace C library
└── user # Userspace programs
```
### Quick Start
On a linux machine, make sure that you have `make` and `curl` in path. The rest
of the tooling (gcc, qemu) will be handled by the build system. For extra convenience,
you could also use `bear` for generating "compile_commands.json". This is useful for helping
clangd pick up the correct paths, and will result in better in-editor diagnostics and warnings.
For development, `clang-format` and `find` will also be useful.
In short, for debian/redhat:
```sh
sudo apt install bear make curl clang-format find
sudo dnf install bear make curl clang-format find
```
Im sure its the same on alpine/arch and friends. You're a linux user, put on those big boy pants
and figure it out. For more info you can check `make help`.
```sh
make get_toolchain # Dont worry, is will land locally inside project directory
make -j$(nproc)
make qemu
```
To generate "compile_commands.json":
```sh
make clean # To get a full build
bear -- make -j$(nproc)
```
The project can be cleaned with:
```sh
make clean # Wipes .o, .d, .elf
make distclean # Wipes the above, but also removes toolchain
```
### Toolchains:
Toolchains:
- https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
- https://github.com/xpack-dev-tools/qemu-riscv-xpack/
@ -64,8 +15,6 @@ make distclean # Wipes the above, but also removes toolchain
> term trap, largely because it was the term used by the PDP11/40 and therefore is the
> conventional Unix term.
### Notes/Misc
| Register | Name | Privilege Level | Description |
|-------------|----------------------------|------------------|-----------------------------------------------------------------------------|
| `mstatus` | Machine Status Register | Machine | Holds global interrupt enable, previous privilege mode, etc. |
@ -84,18 +33,12 @@ make distclean # Wipes the above, but also removes toolchain
| `mip` | Machine Interrupt Pending | Machine | Indicates pending interrupts. |
| `mie` | Machine Interrupt Enable | Machine | Controls which interrupts are enabled. |
### TODO
- [x] Kassert, some macro in the form of `ASSERT(condition, "This went wrong")`
- [ ] [FatFs](https://elm-chan.org/fsw/ff/)
- [ ] Integrate [Kconfig](https://github.com/ulfalizer/Kconfiglib)
- [ ] Klog, or some form of logging that is directable and more than just kprintf
# Notes
### Libc Implementations
## Libc Implementations
- [Libc reference](https://discapes.github.io/libc-reference/)
- [uClibc](https://uclibc.org/)
- [musl libc](https://musl.libc.org/)
- [dietlibc](http://www.fefe.de/dietlibc/)
[uClibc](https://uclibc.org/)
[musl libc](https://musl.libc.org/)
[dietlibc](http://www.fefe.de/dietlibc/)
[Comparison of C/POSIX standard library implementations for Linux](https://www.etalabs.net/compare_libcs.html) (by musl author)

View file

@ -1,5 +1,3 @@
#ifndef KERNEL_CONFIG_H
#define KERNEL_CONFIG_H
/*
* Number of CPU's For now, this is hard-coded here. It will likely be
* dynamically discovered in the future.
@ -8,4 +6,3 @@
/* Maximum number of files open */
#define NOFILE 10
#endif // KERNEL_CONFIG_H

View file

@ -1,36 +0,0 @@
#ifndef BANNER_H
#define BANNER_H
unsigned char banner[] = {
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x34, 0x6d, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20,
0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x37, 0x38, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x5f, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x34, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x38, 0x6d, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x31, 0x34, 0x6d, 0x7c, 0x20, 0x5c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x5f, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x30, 0x38, 0x6d, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x30, 0x39, 0x6d, 0x7c, 0x5f, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x33, 0x6d, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20,
0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x39, 0x6d, 0x7c, 0x20, 0x20,
0x5c, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x33, 0x6d, 0x5f, 0x20,
0x5c, 0x20, 0x27, 0x5f, 0x20, 0x5c, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x34, 0x6d,
0x5f, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39,
0x38, 0x6d, 0x27, 0x5f, 0x20, 0x5c, 0x20, 0x2f, 0x20, 0x5f, 0x20, 0x5c, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x34, 0x6d, 0x7c, 0x20, 0x7c, 0x5c, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x38, 0x6d, 0x5f, 0x5f, 0x2f, 0x20, 0x7c, 0x5f, 0x29, 0x20, 0x7c,
0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x39, 0x6d, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c,
0x20, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x36, 0x33, 0x6d, 0x7c, 0x20, 0x7c, 0x20, 0x7c,
0x20, 0x20, 0x5f, 0x5f, 0x2f, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39,
0x39, 0x6d, 0x7c, 0x5f, 0x7c, 0x20, 0x5c, 0x5f, 0x7c, 0x5c, 0x5f, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x36, 0x33, 0x6d, 0x5f, 0x5f, 0x7c, 0x20, 0x2e, 0x5f, 0x5f, 0x2f, 0x20, 0x5c, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x36, 0x34, 0x6d, 0x5f, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x32, 0x38, 0x6d, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x5f, 0x7c, 0x1b, 0x5b,
0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x36, 0x34, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x32, 0x38, 0x6d, 0x20, 0x20, 0x7c, 0x5f,
0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x32, 0x39, 0x6d, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x33, 0x6d, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x30, 0x6d};
unsigned int banner_len = 531;
#endif // BANNER_H

45
kern/ispinlock.c Normal file
View file

@ -0,0 +1,45 @@
#include "ispinlock.h"
void spinlock_init(spinlock_t *l) {
l->v = 0;
}
__attribute__((warn_unused_result)) bool spin_trylock(spinlock_t *l) {
uint32_t old;
// old = xchg_acquire(&l->v, 1) using AMO
__asm__ volatile("amoswap.w.aq %0, %2, (%1)\n" : "=&r"(old) : "r"(&l->v), "r"(1u) : "memory");
return old == 0;
}
void spin_unlock(spinlock_t *l) {
// Release: store 0 with .rl ordering.
uint32_t dummy;
__asm__ volatile("amoswap.w.rl %0, %2, (%1)\n" : "=&r"(dummy) : "r"(&l->v), "r"(0u) : "memory");
}
// Optional: tiny pause/backoff (works even if Zihintpause isn't present).
// See: https://github.com/riscv/riscv-isa-manual/blob/main/src/zihintpause.adoc
static inline void cpu_relax(void) {
#if defined(__riscv_zihintpause)
__asm__ volatile("pause");
#else
__asm__ volatile("nop");
#endif
}
// Test-and-test-and-set acquire with polite spinning + exponential backoff.
void spin_lock(spinlock_t *l) {
unsigned backoff = 1;
for (;;) {
if (spin_trylock(l))
return;
// Contended: spin on plain loads (no AMO) until it looks free.
while (__atomic_load_n(&l->v, __ATOMIC_RELAXED) != 0) {
for (unsigned i = 0; i < backoff; ++i) cpu_relax();
if (backoff < 1u << 12)
backoff <<= 1;
}
// Try again; loop.
}
}

11
kern/ispinlock.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include <stdint.h>
typedef struct {
volatile uint32_t v; // 0 = unlocked, 1 = locked
} spinlock_t;
void spinlock_init(spinlock_t *l);
bool spin_trylock(spinlock_t *l);
void spin_unlock(spinlock_t *l);
void spin_lock(spinlock_t *l);

76
kern/kalloc.c Normal file
View file

@ -0,0 +1,76 @@
#include <ispinlock.h>
#include <kalloc.h>
#include <memory.h>
#include <panic.h>
#include <riscv.h>
#include <string.h>
#include <types.h>
// Physical memory allocator, for user processes,
// kernel stacks, page-table pages,
// and pipe buffers. Allocates whole 4096-byte pages.
/** Free list of physical pages. */
void freerange(void *physaddr_start, void *physaddr_end);
/** First address after kernel. Provided kernel.ld */
extern char kernel_end[];
/** A run is a node in the free list. */
struct Run {
struct Run *next;
};
/** Kernel memory allocator. */
struct {
spinlock_t lock;
struct Run *freelist;
} kmem;
void kalloc_init() {
spinlock_init(&kmem.lock);
freerange(kernel_end, (void *)PHYSTOP);
}
void freerange(void *physaddr_start, void *physaddr_end) {
char *p;
p = (char *)PGROUNDUP((u64)physaddr_start);
for (; p + PGSIZE <= (char *)physaddr_end; p += PGSIZE) kfree(p);
}
void kfree(void *pa) {
struct Run *r;
// Assert that page is a ligned to a page boundary and that its correctly
// sized
if (((u64)pa % PGSIZE) != 0 || (char *)pa < kernel_end || (u64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct Run *)pa;
spin_lock(&kmem.lock);
r->next = kmem.freelist;
kmem.freelist = r;
spin_unlock(&kmem.lock);
}
void *kalloc(void) {
struct Run *r;
spin_lock(&kmem.lock);
r = kmem.freelist;
if (r)
kmem.freelist = r->next;
spin_unlock(&kmem.lock);
if (r)
memset((char *)r, 5, PGSIZE); // fill with junk
return (void *)r;
}

33
kern/kalloc.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef KALLOC_KERNEL_H
#define KALLOC_KERNEL_H
/**
* Kernel memory allocator
*
* Allocate one 4096-byte page of physical memory.
* Returns a pointer that the kernel can use.
* Returns 0 if the memory cannot be allocated.
* See: kalloc.c
*/
void *kalloc(void);
/**
* Kernel memory allocator
*
* Free the page of physical memory pointed at by pa,
* which normally should have been returned by a
* call to kalloc(). (The exception is when
* initializing the allocator; see kinit above.)
* See: kalloc.c
*/
void kfree(void *);
/**
* Initialize kernel memory allocator
*
* Called by main() on the way to the kernel's main loop.
* See: kalloc.c
*/
void kalloc_init(void);
#endif

103
kern/kprint.c Normal file
View file

@ -0,0 +1,103 @@
#include <stdarg.h>
#include <stdbool.h>
static void append_char(char **buf, size_t *remaining, char c) {
if (*remaining > 1) { // Leave space for null terminator
**buf = c;
(*buf)++;
(*remaining)--;
}
}
static void append_str(char **buf, size_t *remaining, const char *str) {
while (*str) {
append_char(buf, remaining, *str++);
}
}
static void append_int(char **buf, size_t *remaining, int value, int base) {
char tmp[32];
const char *digits = "0123456789abcdef";
bool neg = false;
int i = 0;
if (base == 10 && value < 0) {
neg = true;
value = -value;
}
do {
tmp[i++] = digits[value % base];
value /= base;
} while (value && i < (int)sizeof(tmp));
if (neg) {
tmp[i++] = '-';
}
while (i--) {
append_char(buf, remaining, tmp[i]);
}
}
int kvsnprintf(char *buf, size_t size, const char *fmt, va_list args) {
char *p = buf;
size_t remaining = size;
while (*fmt) {
if (*fmt != '%') {
append_char(&p, &remaining, *fmt++);
continue;
}
fmt++; // skip '%'
switch (*fmt) {
case 's':
append_str(&p, &remaining, va_arg(args, const char *));
break;
case 'd':
append_int(&p, &remaining, va_arg(args, int), 10);
break;
case 'x':
append_int(&p, &remaining, va_arg(args, unsigned int), 16);
break;
case 'c':
append_char(&p, &remaining, (char)va_arg(args, int));
break;
case '%':
append_char(&p, &remaining, '%');
break;
default:
append_char(&p, &remaining, '?');
break;
}
fmt++;
}
if (remaining > 0) {
*p = '\0';
} else {
buf[size - 1] = '\0';
}
return (int)(p - buf);
}
int ksnprintf(char *buf, size_t size, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int ret = kvsnprintf(buf, size, fmt, args);
va_end(args);
return ret;
}
void kprintf(const char *fmt, ...) {
char buffer[256];
va_list args;
va_start(args, fmt);
kvsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
// Now send buffer to your console/serial output
console_write(buffer);
}

View file

@ -1,16 +0,0 @@
#include <panic.h>
#include <stdio.h>
#define assert(cond) \
do { \
if (!(cond)) { \
PANIC("Assertion failed: %s\n", #cond); \
} \
} while (0)
#define assert_msg(cond, fmt, ...) \
do { \
if (!(cond)) { \
PANIC("Assertion failed: %s: " fmt, #cond, ##__VA_ARGS__); \
} \
} while (0)

View file

@ -1,35 +0,0 @@
#include "badrand.h"
#include <stdint.h>
#define PRAND_BUILD_SEED \
((uint64_t)(__TIME__[0]) * (uint64_t)(__TIME__[1]) * (uint64_t)(__TIME__[3]) * (uint64_t)(__TIME__[4]) * \
(uint64_t)(__TIME__[6]) * (uint64_t)(__TIME__[7]))
static uint64_t seed = PRAND_BUILD_SEED * 6364136223846793005ULL + 1;
uint64_t badrand() {
seed = seed * 6364136223846793005ULL + 1;
return seed;
}
uint64_t badrand_range(uint64_t min, uint64_t max) {
uint64_t range = max - min + 1;
uint64_t x;
uint64_t limit = UINT64_MAX - (UINT64_MAX % range);
do {
x = badrand();
} while (x > limit);
return min + (x % range);
}
void sbadprand(uint64_t s) {
if (s) {
seed ^= (s * 0x9e3779b97f4a7c15ULL) + (seed << 6) + (seed >> 2);
} else {
seed ^= PRAND_BUILD_SEED;
}
}
#undef PRAND_BUILD_SEED

View file

@ -1,43 +0,0 @@
#ifndef BADRAND_H
#define BADRAND_H
#include <stdint.h>
/*
* This is a PRNG for non-cryptographic use.
*
* See:
* https://en.wikipedia.org/wiki/Linear_congruential_generator
*/
/**
* @brief Sets the seed for the PRNG.
*
* @param s The specific seed value or zero. If zero is passed, it will call
* rand_reseed().
*/
void sbadrand(uint64_t s);
/**
* @brief Generates a pseudo-random 64-bit number.
*
* Uses a simple Linear Congruential Generator (LCG) to produce
* a sequence of pseudo-random numbers.
*
* @return A pseudo-random 64-bit unsigned integer.
*/
uint64_t badrand();
/**
* @brief Generates a random number within a specified range.
*
* Produces a random number in the inclusive range [min, max].
* Ensures uniform distribution by applying a modulo operation.
*
* @param min The lower bound of the range (inclusive).
* @param max The upper bound of the range (inclusive).
* @return A random number between min and max.
*/
uint64_t badrand_range(uint64_t min, uint64_t max);
#endif // BADRAND_H

View file

@ -1,139 +0,0 @@
#include <assert.h>
#include <buddy.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#define MAX_ORDER 22 // 2^22 * min_block_size = max allocatable block
#define MIN_BLOCK_SIZE 32 // Smallest allocatable block
typedef struct free_block {
struct free_block *next;
} free_block_t;
typedef struct {
uint8_t order;
} block_header_t;
static free_block_t *free_lists[MAX_ORDER + 1];
uintptr_t heap_start = (uintptr_t)&__heap_start;
uintptr_t heap_end = (uintptr_t)&__heap_end;
// Utility: round up to next power of two
static size_t next_pow2(size_t x) {
if (x <= 1)
return 1;
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
#if UINTPTR_MAX > 0xffffffff
x |= x >> 32;
#endif
return x + 1;
}
// Find order for size
static int size_to_order(size_t size) {
size_t needed = (size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : size;
size_t block_size = next_pow2(needed);
int order = 0;
while ((MIN_BLOCK_SIZE << order) < block_size) {
order++;
}
return order;
}
// Initialize allocator
void buddy_init(uintptr_t start, uintptr_t end) {
heap_start = (start + MIN_BLOCK_SIZE - 1) & ~(MIN_BLOCK_SIZE - 1);
heap_end = end & ~(MIN_BLOCK_SIZE - 1);
// Clear free lists
for (int i = 0; i <= MAX_ORDER; i++) free_lists[i] = NULL;
// Put the whole region as one big block
size_t total_size = heap_end - heap_start;
int order = MAX_ORDER;
while ((MIN_BLOCK_SIZE << order) > total_size && order > 0) order--;
free_block_t *block = (free_block_t *)heap_start;
block->next = NULL;
free_lists[order] = block;
}
// Allocate memory
void *buddy_alloc(size_t size) {
int order = size_to_order(size);
for (int i = order; i <= MAX_ORDER; i++) {
if (free_lists[i]) {
// Remove block from this list
free_block_t *block = free_lists[i];
free_lists[i] = block->next;
// Split down to requested order
while (i > order) {
i--;
uintptr_t buddy_addr = (uintptr_t)block + (MIN_BLOCK_SIZE << i);
free_block_t *buddy = (free_block_t *)buddy_addr;
buddy->next = free_lists[i];
free_lists[i] = buddy;
}
/*
* Here, we install a header into the block. This will allow us to use free, without
* specifying size, since it can read the order from one byte before the block start.
*/
{
block_header_t *hdr = (block_header_t *)block;
hdr->order = order;
return (void *)(hdr + 1); // return pointer after header
// return (void *)block; // Regular block return for reference
}
}
}
return NULL; // Out of memory
}
// Free memory
int buddy_free(void *ptr) {
block_header_t *hdr = (block_header_t *)ptr - 1;
int order = hdr->order;
assert_msg(order != MAX_ORDER, "The buddy freelist header seems to have been corrupted.");
uintptr_t addr = (uintptr_t)ptr;
while (order < MAX_ORDER) {
uintptr_t buddy_addr = addr ^ (MIN_BLOCK_SIZE << order);
// Check if buddy is in free list
free_block_t **prev = &free_lists[order];
free_block_t *cur = free_lists[order];
while (cur) {
if ((uintptr_t)cur == buddy_addr) {
// Remove buddy from list
*prev = cur->next;
// Merge
if (buddy_addr < addr)
addr = buddy_addr;
order++;
goto try_merge;
}
prev = &cur->next;
cur = cur->next;
}
break; // Buddy not free, stop
try_merge:;
}
free_block_t *block = (free_block_t *)addr;
block->next = free_lists[order];
free_lists[order] = block;
return order;
}

View file

@ -1,22 +0,0 @@
#ifndef BUDDY_H
#define BUDDY_H
#include <stddef.h>
#include <stdint.h>
extern uintptr_t heap_start;
extern uintptr_t heap_end;
extern char __heap_start;
extern char __heap_end;
void buddy_init(uintptr_t start, uintptr_t end);
void *buddy_alloc(size_t size);
int buddy_free(void *ptr);
/* Returns total heap memory managed by buddy allocator in bytes */
static inline size_t buddy_total_bytes(void) {
return (uintptr_t)&__heap_end - (uintptr_t)&__heap_start;
}
#endif // BUDDY_H

View file

@ -1,136 +1,91 @@
#ifndef ENDIAN_KERNEL_H
#define ENDIAN_KERNEL_H
#include <stdint.h>
#include <types.h>
/** Swap byte order of 16-bit value */
static inline u16 swap16(u16 x) {
return (x >> 8) | (x << 8);
}
static inline u16 swap16(u16 x) { return (x >> 8) | (x << 8); }
/** Swap byte order of 32-bit value */
static inline u32 swap32(u32 x) {
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) | ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) |
((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
}
/** Swap byte order of 64-bit value */
static inline u64 swap64(u64 x) {
return ((x >> 56) & 0x00000000000000ffULL) | ((x >> 40) & 0x000000000000ff00ULL) |
((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 8) & 0x00000000ff000000ULL) |
((x << 8) & 0x000000ff00000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) |
((x << 40) & 0x00ff000000000000ULL) | ((x << 56) & 0xff00000000000000ULL);
return ((x >> 56) & 0x00000000000000ffULL) |
((x >> 40) & 0x000000000000ff00ULL) |
((x >> 24) & 0x0000000000ff0000ULL) |
((x >> 8) & 0x00000000ff000000ULL) |
((x << 8) & 0x000000ff00000000ULL) |
((x << 24) & 0x0000ff0000000000ULL) |
((x << 40) & 0x00ff000000000000ULL) |
((x << 56) & 0xff00000000000000ULL);
}
#ifdef __LITTLE_ENDIAN__
/** Convert 16-bit value to little-endian */
static inline u16 to_le16(u16 x) {
return x;
}
static inline u16 to_le16(u16 x) { return x; }
/** Convert 16-bit little-endian value to host */
static inline u16 from_le16(u16 x) {
return x;
}
static inline u16 from_le16(u16 x) { return x; }
/** Convert 32-bit value to little-endian */
static inline u32 to_le32(u32 x) {
return x;
}
static inline u32 to_le32(u32 x) { return x; }
/** Convert 32-bit little-endian value to host */
static inline u32 from_le32(u32 x) {
return x;
}
static inline u32 from_le32(u32 x) { return x; }
/** Convert 64-bit value to little-endian */
static inline u64 to_le64(u64 x) {
return x;
}
static inline u64 to_le64(u64 x) { return x; }
/** Convert 64-bit little-endian value to host */
static inline u64 from_le64(u64 x) {
return x;
}
static inline u64 from_le64(u64 x) { return x; }
/** Convert 16-bit value to big-endian */
static inline u16 to_be16(u16 x) {
return swap16(x);
}
static inline u16 to_be16(u16 x) { return swap16(x); }
/** Convert 16-bit big-endian value to host */
static inline u16 from_be16(u16 x) {
return swap16(x);
}
static inline u16 from_be16(u16 x) { return swap16(x); }
/** Convert 32-bit value to big-endian */
static inline u32 to_be32(u32 x) {
return swap32(x);
}
static inline u32 to_be32(u32 x) { return swap32(x); }
/** Convert 32-bit big-endian value to host */
static inline u32 from_be32(u32 x) {
return swap32(x);
}
static inline u32 from_be32(u32 x) { return swap32(x); }
/** Convert 64-bit value to big-endian */
static inline u64 to_be64(u64 x) {
return swap64(x);
}
static inline u64 to_be64(u64 x) { return swap64(x); }
/** Convert 64-bit big-endian value to host */
static inline u64 from_be64(u64 x) {
return swap64(x);
}
static inline u64 from_be64(u64 x) { return swap64(x); }
#else // Big-endian
/** Convert 16-bit value to little-endian */
static inline u16 to_le16(u16 x) {
return swap16(x);
}
static inline u16 to_le16(u16 x) { return swap16(x); }
/** Convert 16-bit little-endian value to host */
static inline u16 from_le16(u16 x) {
return swap16(x);
}
static inline u16 from_le16(u16 x) { return swap16(x); }
/** Convert 32-bit value to little-endian */
static inline u32 to_le32(u32 x) {
return swap32(x);
}
static inline u32 to_le32(u32 x) { return swap32(x); }
/** Convert 32-bit little-endian value to host */
static inline u32 from_le32(u32 x) {
return swap32(x);
}
static inline u32 from_le32(u32 x) { return swap32(x); }
/** Convert 64-bit value to little-endian */
static inline u64 to_le64(u64 x) {
return swap64(x);
}
static inline u64 to_le64(u64 x) { return swap64(x); }
/** Convert 64-bit little-endian value to host */
static inline u64 from_le64(u64 x) {
return swap64(x);
}
static inline u64 from_le64(u64 x) { return swap64(x); }
/** Convert 16-bit value to big-endian */
static inline u16 to_be16(u16 x) {
return x;
}
static inline u16 to_be16(u16 x) { return x; }
/** Convert 16-bit big-endian value to host */
static inline u16 from_be16(u16 x) {
return x;
}
static inline u16 from_be16(u16 x) { return x; }
/** Convert 32-bit value to big-endian */
static inline u32 to_be32(u32 x) {
return x;
}
static inline u32 to_be32(u32 x) { return x; }
/** Convert 32-bit big-endian value to host */
static inline u32 from_be32(u32 x) {
return x;
}
static inline u32 from_be32(u32 x) { return x; }
/** Convert 64-bit value to big-endian */
static inline u64 to_be64(u64 x) {
return x;
}
static inline u64 to_be64(u64 x) { return x; }
/** Convert 64-bit big-endian value to host */
static inline u64 from_be64(u64 x) {
return x;
}
static inline u64 from_be64(u64 x) { return x; }
#endif // __LITTLE_ENDIAN__

View file

@ -1,102 +0,0 @@
#include "freelist.h"
#include "stddef.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct FreeListBlock {
struct FreeListBlock *next;
};
/* Initialize the FreeList */
int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize) {
size_t size = ALIGN(itemsize);
if (!fl || end <= start)
return EXIT_FAILURE;
fl->start = start;
fl->end = end;
fl->size = size;
fl->allocated = 0;
FreeListBlock *block = (FreeListBlock *)start;
for (size_t i = 0; i < fl_capacity(fl); i++) {
block->next = (FreeListBlock *)((void *)block + size);
block = block->next;
}
block->next = NULL;
fl->free = (FreeListBlock *)start;
return EXIT_SUCCESS;
}
/* Allocate some memory from the FreeList */
void *fl_alloc(FreeList *fl) {
if (!fl->free)
return NULL;
FreeListBlock *m = fl->free;
fl->free = fl->free->next;
fl->allocated++;
memset((void *)m, 0, sizeof(FreeListBlock));
return ((void *)m);
}
/* Return some memory to the FreeList */
int fl_free(FreeList *fl, void *ptr) {
if (!fl_is_managed(fl, ptr)) {
return EXIT_FAILURE; /* We cant free memory we do not own */
}
FreeListBlock *block = (FreeListBlock *)(uintptr_t)ptr;
block->next = fl->free;
fl->free = block;
fl->allocated--;
return EXIT_SUCCESS;
}
/* Returns how many slots are occupied */
size_t fl_allocated(FreeList *fl) {
return fl->allocated;
}
/* Returns how many free slots are available (O(1)) */
size_t fl_available(FreeList *fl) {
return fl_capacity(fl) - fl->allocated;
}
/* Returns the total amount of items the freelist will hold */
size_t fl_capacity(FreeList *fl) {
return (fl->end - fl->start) / fl->size;
}
/* Check if a piece of memory is managed by the FreeList */
int fl_is_managed(FreeList *fl, void *ptr) {
return ((uintptr_t)ptr >= fl->start && (uintptr_t)ptr < fl->end);
}
/* Returns the ratio of metadata versus data as a scalar in range 0..1 */
float fl_utilization(FreeList *fl, size_t itemsize) {
return (float)itemsize / fl->size;
}
/* Walks the free pages/slots, returns total count (O(n), given no cycles) */
size_t fl_check(FreeList *fl) {
int avail = 0;
FreeListBlock *cursor = fl->free;
while (cursor->next != NULL) {
avail++;
cursor = cursor->next;
}
return avail;
}

View file

@ -1,40 +0,0 @@
#ifndef FREELIST_H
#define FREELIST_H
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
/* Align to nearest multiple of align */
static inline size_t align_up_to(size_t n, size_t align) {
return (n + align - 1) & ~(align - 1);
}
/* Fiddle these around according to your need. Delete or check makefile */
#ifdef FREELIST_ALIGN
#define ALIGN(x) (align_up_to(x, sizeof(void *)))
#else
#define ALIGN(x) (x)
#endif
typedef struct FreeListBlock FreeListBlock;
typedef struct {
FreeListBlock *free;
uintptr_t start;
uintptr_t end;
size_t size;
size_t allocated;
} FreeList;
int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize);
int fl_free(FreeList *fl, void *ptr);
int fl_is_managed(FreeList *fl, void *ptr);
void *fl_alloc(FreeList *fl);
size_t fl_check(FreeList *fl);
size_t fl_allocated(FreeList *fl);
size_t fl_available(FreeList *fl);
size_t fl_capacity(FreeList *fl);
float fl_utilization(FreeList *fl, size_t itemsize);
#endif // FREELIST_H

View file

@ -1,21 +1,29 @@
#include <assert.h>
#include <memory.h>
#include <stdlib.h>
#include <string.h>
#include <uart.h>
int memory_sweep(const uintptr_t start, const uintptr_t end) {
assert_msg(start < end, "Start needs to be before end.");
uintptr_t sweeper = start;
#define MAX_PROBE_SIZE (256 * 1024 * 1024) // Probe up to 256 MiB max
#define PROBE_STEP 0x1000 // Probe every 4 KiB page
while (sweeper < end) {
*(uint64_t *)sweeper = 0xFAFAFAFABCBCBCBC;
sweeper += sizeof(uint64_t);
size_t probe_memory(void) {
volatile u32 *addr;
u32 test_pattern = 0xA5A5A5A5;
size_t detected = 0;
for (size_t offset = 4096 * 16; offset < MAX_PROBE_SIZE;
offset += PROBE_STEP) {
addr = (volatile u32 *)(KERNBASE + offset);
u32 old = *addr;
*addr = test_pattern;
if (*addr != test_pattern) {
break; // Memory not readable/writable here, stop probing
}
*addr = old; // restore original data
detected = offset + PROBE_STEP;
}
sweeper -= sizeof(uint64_t);
while (sweeper != start) {
assert(*(uint64_t *)sweeper == 0xFAFAFAFABCBCBCBC);
sweeper -= sizeof(uint64_t);
}
return EXIT_SUCCESS;
return detected;
}

View file

@ -8,8 +8,9 @@
#define PHYSTOP (KERNBASE + 128 * 1024 * 1024)
/**
* Set and fetch routine for checking memory.
* Returns size in bytes of detected RAM In qemu, it requires a trap handler to
* handle the interrupt when accessing unavailable memory.
*/
int memory_sweep(const uintptr_t start, const uintptr_t end);
size_t probe_memory(void);
#endif // MEMORY_KERNEL_H
#endif

View file

@ -43,251 +43,269 @@
#include "mini-printf.h"
static int mini_strlen(const char *s) {
int len = 0;
while (s[len] != '\0') len++;
return len;
static int
mini_strlen(const char *s)
{
int len = 0;
while (s[len] != '\0') len++;
return len;
}
static int mini_itoa(long value, unsigned int radix, int uppercase, int unsig, char *buffer) {
char *pbuffer = buffer;
int negative = 0;
int i, len;
static int
mini_itoa(long value, unsigned int radix, int uppercase, int unsig,
char *buffer)
{
char *pbuffer = buffer;
int negative = 0;
int i, len;
/* No support for unusual radixes. */
if (radix > 16)
return 0;
/* No support for unusual radixes. */
if (radix > 16)
return 0;
if (value < 0 && !unsig) {
negative = 1;
value = -value;
}
if (value < 0 && !unsig) {
negative = 1;
value = -value;
}
/* This builds the string back to front ... */
do {
int digit = value % radix;
*(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10);
value /= radix;
} while (value > 0);
/* This builds the string back to front ... */
do {
int digit = value % radix;
*(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10);
value /= radix;
} while (value > 0);
if (negative)
*(pbuffer++) = '-';
if (negative)
*(pbuffer++) = '-';
*(pbuffer) = '\0';
*(pbuffer) = '\0';
/* ... now we reverse it (could do it recursively but will
* conserve the stack space) */
len = (pbuffer - buffer);
for (i = 0; i < len / 2; i++) {
char j = buffer[i];
buffer[i] = buffer[len - i - 1];
buffer[len - i - 1] = j;
}
/* ... now we reverse it (could do it recursively but will
* conserve the stack space) */
len = (pbuffer - buffer);
for (i = 0; i < len / 2; i++) {
char j = buffer[i];
buffer[i] = buffer[len-i-1];
buffer[len-i-1] = j;
}
return len;
return len;
}
static int mini_pad(char *ptr, int len, char pad_char, int pad_to, char *buffer) {
int i;
int overflow = 0;
char *pbuffer = buffer;
if (pad_to == 0)
pad_to = len;
if (len > pad_to) {
len = pad_to;
overflow = 1;
}
for (i = pad_to - len; i > 0; i--) {
*(pbuffer++) = pad_char;
}
for (i = len; i > 0; i--) {
*(pbuffer++) = *(ptr++);
}
len = pbuffer - buffer;
if (overflow) {
for (i = 0; i < 3 && pbuffer > buffer; i++) {
*(pbuffer-- - 1) = '*';
}
}
return len;
static int
mini_pad(char* ptr, int len, char pad_char, int pad_to, char *buffer)
{
int i;
int overflow = 0;
char * pbuffer = buffer;
if(pad_to == 0) pad_to = len;
if(len > pad_to) {
len = pad_to;
overflow = 1;
}
for(i = pad_to - len; i > 0; i --) {
*(pbuffer++) = pad_char;
}
for(i = len; i > 0; i --) {
*(pbuffer++) = *(ptr++);
}
len = pbuffer - buffer;
if(overflow) {
for (i = 0; i < 3 && pbuffer > buffer; i ++) {
*(pbuffer-- - 1) = '*';
}
}
return len;
}
struct mini_buff {
char *buffer, *pbuffer;
unsigned int buffer_len;
char *buffer, *pbuffer;
unsigned int buffer_len;
};
static int _puts(char *s, int len, void *buf) {
if (!buf)
return len;
struct mini_buff *b = buf;
char *p0 = b->buffer;
int i;
/* Copy to buffer */
for (i = 0; i < len; i++) {
if (b->pbuffer == b->buffer + b->buffer_len - 1) {
break;
}
*(b->pbuffer++) = s[i];
}
*(b->pbuffer) = 0;
return b->pbuffer - p0;
static int
_puts(char *s, int len, void *buf)
{
if(!buf) return len;
struct mini_buff *b = buf;
char * p0 = b->buffer;
int i;
/* Copy to buffer */
for (i = 0; i < len; i++) {
if(b->pbuffer == b->buffer + b->buffer_len - 1) {
break;
}
*(b->pbuffer ++) = s[i];
}
*(b->pbuffer) = 0;
return b->pbuffer - p0;
}
#ifdef MINI_PRINTF_ENABLE_OBJECTS
static int (*mini_handler)(void *data, void *obj, int ch, int lhint, char **bf) = 0;
static void (*mini_handler_freeor)(void *data, void *) = 0;
static void *mini_handler_data = 0;
static int (*mini_handler) (void* data, void* obj, int ch, int lhint, char** bf) = 0;
static void (*mini_handler_freeor)(void* data, void*) = 0;
static void * mini_handler_data = 0;
void mini_printf_set_handler(void *data, int (*handler)(void *data, void *obj, int ch, int len_hint, char **buf),
void (*freeor)(void *data, void *buf)) {
mini_handler = handler;
mini_handler_freeor = freeor;
mini_handler_data = data;
void mini_printf_set_handler(
void* data,
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
void (*freeor)(void* data, void* buf))
{
mini_handler = handler;
mini_handler_freeor = freeor;
mini_handler_data = data;
}
#endif
int mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va) {
struct mini_buff b;
b.buffer = buffer;
b.pbuffer = buffer;
b.buffer_len = buffer_len;
if (buffer_len == 0)
buffer = (void *)0;
int n = mini_vpprintf(_puts, (buffer != (void *)0) ? &b : (void *)0, fmt, va);
if (buffer == (void *)0) {
return n;
}
return b.pbuffer - b.buffer;
int
mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va)
{
struct mini_buff b;
b.buffer = buffer;
b.pbuffer = buffer;
b.buffer_len = buffer_len;
if(buffer_len == 0) buffer = (void*) 0;
int n = mini_vpprintf(_puts, (buffer != (void*)0)?&b:(void*)0, fmt, va);
if(buffer == (void*) 0) {
return n;
}
return b.pbuffer - b.buffer;
}
int mini_vpprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, va_list va) {
char bf[24];
char bf2[24];
char ch;
int
mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va)
{
char bf[24];
char bf2[24];
char ch;
#ifdef MINI_PRINTF_ENABLE_OBJECTS
void *obj;
void* obj;
#endif
if (puts == (void *)0) {
/* run puts in counting mode. */
puts = _puts;
buf = (void *)0;
}
int n = 0;
while ((ch = *(fmt++))) {
int len;
if (ch != '%') {
len = 1;
len = puts(&ch, len, buf);
} else {
char pad_char = ' ';
int pad_to = 0;
char l = 0;
char *ptr;
if(puts == (void*)0) {
/* run puts in counting mode. */
puts = _puts; buf = (void*)0;
}
int n = 0;
while ((ch=*(fmt++))) {
int len;
if (ch!='%') {
len = 1;
len = puts(&ch, len, buf);
} else {
char pad_char = ' ';
int pad_to = 0;
char l = 0;
char *ptr;
ch = *(fmt++);
ch=*(fmt++);
/* Zero padding requested */
if (ch == '0')
pad_char = '0';
while (ch >= '0' && ch <= '9') {
pad_to = pad_to * 10 + (ch - '0');
ch = *(fmt++);
}
if (pad_to > (signed int)sizeof(bf)) {
pad_to = sizeof(bf);
}
if (ch == 'l') {
l = 1;
ch = *(fmt++);
}
/* Zero padding requested */
if (ch == '0') pad_char = '0';
while (ch >= '0' && ch <= '9') {
pad_to = pad_to * 10 + (ch - '0');
ch=*(fmt++);
}
if(pad_to > (signed int) sizeof(bf)) {
pad_to = sizeof(bf);
}
if (ch == 'l') {
l = 1;
ch=*(fmt++);
}
switch (ch) {
case 0: goto end;
case 'u':
case 'd':
if (l) {
len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch == 'u'), bf2);
} else {
if (ch == 'u') {
len = mini_itoa((unsigned long)va_arg(va, unsigned int), 10, 0, 1, bf2);
} else {
len = mini_itoa((long)va_arg(va, int), 10, 0, 0, bf2);
}
}
len = mini_pad(bf2, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
switch (ch) {
case 0:
goto end;
case 'u':
case 'd':
if(l) {
len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch=='u'), bf2);
} else {
if(ch == 'u') {
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 10, 0, 1, bf2);
} else {
len = mini_itoa((long) va_arg(va, int), 10, 0, 0, bf2);
}
}
len = mini_pad(bf2, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 'x':
case 'X':
if (l) {
len = mini_itoa(va_arg(va, unsigned long), 16, (ch == 'X'), 1, bf2);
} else {
len = mini_itoa((unsigned long)va_arg(va, unsigned int), 16, (ch == 'X'), 1, bf2);
}
len = mini_pad(bf2, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 'x':
case 'X':
if(l) {
len = mini_itoa(va_arg(va, unsigned long), 16, (ch=='X'), 1, bf2);
} else {
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 16, (ch=='X'), 1, bf2);
}
len = mini_pad(bf2, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 'c':
ch = (char)(va_arg(va, int));
len = mini_pad(&ch, 1, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 'c' :
ch = (char)(va_arg(va, int));
len = mini_pad(&ch, 1, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 's':
ptr = va_arg(va, char *);
len = mini_strlen(ptr);
if (pad_to > 0) {
len = mini_pad(ptr, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
} else {
len = puts(ptr, len, buf);
}
break;
case 's' :
ptr = va_arg(va, char*);
len = mini_strlen(ptr);
if (pad_to > 0) {
len = mini_pad(ptr, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
} else {
len = puts(ptr, len, buf);
}
break;
#ifdef MINI_PRINTF_ENABLE_OBJECTS
case 'O': /* Object by content (e.g. str) */
case 'R': /* Object by representation (e.g. repr)*/
obj = va_arg(va, void *);
len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr);
if (pad_to > 0) {
len = mini_pad(ptr, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
} else {
len = puts(ptr, len, buf);
}
mini_handler_freeor(mini_handler_data, ptr);
break;
case 'O' : /* Object by content (e.g. str) */
case 'R' : /* Object by representation (e.g. repr)*/
obj = va_arg(va, void*);
len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr);
if (pad_to > 0) {
len = mini_pad(ptr, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
} else {
len = puts(ptr, len, buf);
}
mini_handler_freeor(mini_handler_data, ptr);
break;
#endif
default:
len = 1;
len = puts(&ch, len, buf);
break;
}
}
n = n + len;
}
default:
len = 1;
len = puts(&ch, len, buf);
break;
}
}
n = n + len;
}
end:
return n;
return n;
}
int mini_snprintf(char *buffer, unsigned int buffer_len, const char *fmt, ...) {
int ret;
va_list va;
va_start(va, fmt);
ret = mini_vsnprintf(buffer, buffer_len, fmt, va);
va_end(va);
return ret;
int
mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...)
{
int ret;
va_list va;
va_start(va, fmt);
ret = mini_vsnprintf(buffer, buffer_len, fmt, va);
va_end(va);
return ret;
}
int mini_pprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, ...) {
int ret;
va_list va;
va_start(va, fmt);
ret = mini_vpprintf(puts, buf, fmt, va);
va_end(va);
int
mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...)
{
int ret;
va_list va;
va_start(va, fmt);
ret = mini_vpprintf(puts, buf, fmt, va);
va_end(va);
return ret;
return ret;
}

View file

@ -27,6 +27,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MINI_PRINTF__
#define __MINI_PRINTF__
@ -41,31 +42,32 @@ extern "C" {
* void* arguments matching %O and %R are sent to handler as obj.
* the result string created by handler at *buf is freed by freeor.
* */
void mini_printf_set_handler(void *data,
/* handler returns number of chars in *buf; *buf is not NUL-terminated. */
int (*handler)(void *data, void *obj, int ch, int len_hint, char **buf),
void (*freeor)(void *data, void *buf));
void mini_printf_set_handler(
void * data,
/* handler returns number of chars in *buf; *buf is not NUL-terminated. */
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
void (*freeor)(void* data, void* buf));
#endif
/* String IO interface; returns number of bytes written, not including the ending NUL.
* Always appends a NUL at the end, therefore buffer_len shall be at least 1 in normal operation.
* If buffer is NULL or buffer_len is 0, returns number of bytes to be written, not including the ending NUL.
*/
int mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va);
int mini_snprintf(char *buffer, unsigned int buffer_len, const char *fmt, ...);
int mini_vsnprintf(char* buffer, unsigned int buffer_len, const char *fmt, va_list va);
int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...);
/* Stream IO interface; returns number of bytes written.
* If puts is NULL, number of bytes to be written.
* puts shall return number of bytes written.
*/
int mini_vpprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, va_list va);
int mini_pprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, ...);
int mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va);
int mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#define vsnprintf mini_vsnprintf
#define snprintf mini_snprintf
#define snprintf mini_snprintf
#endif

View file

@ -1,16 +1,8 @@
#include "stdbool.h"
#include <mini-printf.h>
#include <stdarg.h>
#include <stdio.h>
#include <uart.h>
volatile int panicked;
volatile int panicked = false;
__attribute__((visibility("hidden"))) void __panic(const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
kvprintf(fmt, ap);
va_end(ap);
panicked = true;
for (;;) asm volatile("wfi");
void panic(char *s) {
panicked = 1;
uart_puts(s);
while (1);
}

View file

@ -1,8 +1,6 @@
#ifndef KERNEL_PANIC_H
#define KERNEL_PANIC_H
#define PANIC(fmt, ...) __panic("[Panic @ %s:%d %s] " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
void panic(char *s);
void __panic(const char *restrict fmt, ...);
#endif // KERNEL_PANIC_H
#endif

View file

@ -1,6 +1,6 @@
#include <proc.h>
Cpu cpus[NCPU];
struct Cpu cpus[NCPU];
/**
* Must be called with interrupts disabled, to prevent race with process being
@ -14,8 +14,8 @@ int cpuid() {
/**
* Return this CPU's cpu struct. Interrupts must be disabled.
*/
Cpu *mycpu(void) {
int id = cpuid();
Cpu *c = &cpus[id];
struct Cpu *mycpu(void) {
int id = cpuid();
struct Cpu *c = &cpus[id];
return c;
}

View file

@ -39,9 +39,7 @@ static inline u64 read_tp() {
}
/** Write thread pointer */
static inline void write_tp(u64 x) {
asm volatile("mv tp, %0" : : "r"(x));
}
static inline void write_tp(u64 x) { asm volatile("mv tp, %0" : : "r"(x)); }
/**
* Read the value of the sstatus register.
@ -62,14 +60,10 @@ static inline void w_sstatus(u64 x) {
}
/** Enable device interrupts */
static inline void intr_on() {
w_sstatus(r_sstatus() | SSTATUS_SIE);
}
static inline void intr_on() { w_sstatus(r_sstatus() | SSTATUS_SIE); }
/** Disable device interrupts */
static inline void intr_off() {
w_sstatus(r_sstatus() & ~SSTATUS_SIE);
}
static inline void intr_off() { w_sstatus(r_sstatus() & ~SSTATUS_SIE); }
/** Are device interrupts enabled? */
static inline int intr_get() {
@ -77,4 +71,4 @@ static inline int intr_get() {
return (x & SSTATUS_SIE) != 0;
}
#endif // RISCV_KERNEL_H
#endif

View file

@ -3,7 +3,8 @@
* (Not mutexes as these are spinning locks).
*/
#include "stddef.h"
// #include <lib/stdio.h>
#include "string.h"
#include <panic.h>
#include <proc.h>
#include <riscv.h>
@ -40,95 +41,84 @@
* On RISC-V, this emits a fence instruction.
*/
/*
* These are from the original xv6 implementation, with only slight modifications on their return type.
*
* push_off/pop_off are like intr_off()/intr_on() except that they are matched:
* it takes two pop_off()s to undo two push_off()s. Also, if interrupts
* are initially off, then push_off, pop_off leaves them off.
/** Initialize Spinlock */
void initlock(struct Spinlock *lk, char *name) {
lk->name = name;
lk->locked = 0;
lk->cpu = 0;
}
/**
* Acquire the lock.
* Loops (spins) until the lock is acquired.
* Panics if the lock is already held by this cpu.
*/
void acquire(struct Spinlock *lk) {
push_off(); // disable interrupts to avoid deadlock.
uint32_t push_off(void) {
int old = intr_get();
Cpu *cpu = mycpu();
if (holding(lk)) // If the lock is already held, panic.
panic("acquire");
intr_off();
// Spin until aquired. See file header for details
while (__sync_lock_test_and_set(&lk->locked, 1) != 0);
if (cpu->noff == 0)
cpu->intena = old;
__sync_synchronize(); // No loads/stores after this point
cpu->noff += 1;
return cpu->noff;
// Record info about lock acquisition for holding() and debugging.
lk->cpu = mycpu();
}
uint32_t pop_off(void) {
Cpu *cpu = mycpu();
/**
* Release the lock.
* Panics if the lock is not held.
*/
void release(struct Spinlock *lk) {
if (!holding(lk)) // If the lock is not held, panic.
panic("release");
if (intr_get())
PANIC("pop_off - interruptible");
lk->cpu = 0; // 0 means unheld
__sync_synchronize(); // No loads/stores after this point
__sync_lock_release(&lk->locked); // Essentially lk->locked = 0
if (cpu->noff < 1)
PANIC("pop_off when cpu->noff < 1");
cpu->noff -= 1;
if (cpu->noff == 0 && cpu->intena)
intr_on();
return cpu->noff;
}
void spinlock_init(spinlock_t *l) {
l->v = 0;
l->cpu = NULL;
}
__attribute__((warn_unused_result)) bool spin_trylock(spinlock_t *l) {
uint32_t old;
// old = xchg_acquire(&l->v, 1) using AMO
__asm__ volatile("amoswap.w.aq %0, %2, (%1)\n" : "=&r"(old) : "r"(&l->v), "r"(1u) : "memory");
return old == 0;
}
void spin_unlock(spinlock_t *l) {
if (!spin_is_holding(l))
PANIC("Unlocking a spinlock that is not held by the locking cpu!");
/* TODO: Replace with corresponding __atomic builtins */
__sync_lock_release(&l->v);
__sync_synchronize();
l->cpu = NULL;
pop_off();
}
/**
* Test-and-test-and-set acquire with polite spinning + exponential backoff.
*/
void spin_lock(spinlock_t *l) {
uint32_t backoff = 1;
for (;;) {
if (spin_trylock(l)) {
l->cpu = mycpu();
push_off();
return;
}
while (__atomic_load_n(&l->v, __ATOMIC_RELAXED) != 0) {
for (uint32_t i = 0; i < backoff; ++i)
__asm__ volatile("nop"); /* NOTE: Pause can be used here if supported */
if (backoff < 1u << 12)
backoff <<= 1;
}
}
}
/**
* Check whether this cpu is holding the lock.
* Interrupts must be off.
*/
bool spin_is_holding(spinlock_t *l) {
// Check whether this cpu is holding the lock.
// Interrupts must be off.
int holding(struct Spinlock *lk) {
int r;
r = (l->v && l->cpu == mycpu());
r = (lk->locked && lk->cpu == mycpu());
return r;
}
// push_off/pop_off are like intr_off()/intr_on() except that they are matched:
// it takes two pop_off()s to undo two push_off()s. Also, if interrupts
// are initially off, then push_off, pop_off leaves them off.
void push_off(void) {
int old = intr_get();
intr_off();
if (mycpu()->noff == 0)
mycpu()->intena = old;
mycpu()->noff += 1;
}
void pop_off(void) {
struct Cpu *c = mycpu();
if (intr_get())
panic("pop_off - interruptible");
if (c->noff < 1) {
{
// TODO: Remove this block when fixed
char amt[100];
itoa(c->noff, amt, 10);
uart_puts(amt);
}
panic("pop_off");
}
c->noff -= 1;
if (c->noff == 0 && c->intena)
intr_on();
}

View file

@ -1,22 +1,51 @@
#ifndef KERNEL_SPINLOCK_H
#define KERNEL_SPINLOCK_H
#ifndef KERNEL_Spinlock_H
#define KERNEL_Spinlock_H
#include <proc.h>
#include <stdbool.h>
#include <stdint.h>
typedef struct {
volatile uint32_t v; // 0 = unlocked, 1 = locked
Cpu *cpu;
} spinlock_t;
/** Mutual exclusion spin lock */
struct Spinlock {
u32 locked; // Is the lock held?
uint32_t push_off(void);
uint32_t pop_off(void);
// NOTE: Perhaps feature gate this?
void spinlock_init(spinlock_t *l);
bool spin_trylock(spinlock_t *l);
void spin_unlock(spinlock_t *l);
bool spin_is_holding(spinlock_t *l);
void spin_lock(spinlock_t *l);
// For debugging:
char *name; // Name of lock.
struct Cpu *cpu; // The cpu holding the lock.
};
#endif // KERNEL_SPINLOCK_H
/**
* Acquire the lock.
* Loops (spins) until the lock is acquired.
* Panics if the lock is already held by this cpu.
*/
void acquire(struct Spinlock *);
/**
* Check whether this cpu is holding the lock.
* Interrupts must be off.
*/
int holding(struct Spinlock *);
/**
* Initialize Spinlock
*/
void initlock(struct Spinlock *, char *);
/**
* Release the lock.
* Panics if the lock is not held.
*/
void release(struct Spinlock *);
/**
* @brief push_off/pop_off are like intr_off()/intr_on() except that they are
* matched: it takes two pop_off()s to undo two push_off()s. Also, if
* interrupts are initially off, then push_off, pop_off leaves them off.
*/
void push_off(void);
/** @copydoc pop_off */
void pop_off(void);
#endif

View file

@ -8,4 +8,4 @@ typedef __builtin_va_list va_list;
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#endif // _STDARG_H
#endif

View file

@ -1,8 +0,0 @@
#ifndef _STDBOOL_H
#define _STDBOOL_H
/*TODO*/
typedef char bool;
enum { false = 0, true = 1 };
#endif // _STDBOOL_H

View file

@ -1,13 +0,0 @@
#ifndef STDDEF_H
#define STDDEF_H
#include <stdint.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
#ifndef size_t
#define size_t uint64_t
#endif
#endif // STDDEF_H

View file

@ -1,42 +1,16 @@
#ifndef STDINT_H
#define STDINT_H
#pragma once
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long u64;
typedef char i8;
typedef short i16;
typedef int i32;
typedef long i64;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long uint64_t;
typedef uint64_t size_t;
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long int64_t;
typedef uint64_t size_t;
typedef uint64_t uintptr_t;
#define INT8_MIN (-128)
#define INT16_MIN (-32767 - 1)
#define INT32_MIN (-2147483647 - 1)
#define INT64_MIN (-__INT64_C(9223372036854775807) - 1)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX (__INT64_C(9223372036854775807))
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX (__UINT64_C(18446744073709551615))
#endif // STDINT_H
// typedef u8 bool;

View file

@ -1,33 +0,0 @@
#include <mini-printf.h>
#include <stddef.h>
#include <stdio.h>
#include <uart.h>
/** Helper routine to put characters into our uart device */
static int stdout_puts(char *s, int len, void *unused) {
(void)unused;
for (int i = 0; i < len; i++) uart_putc(s[i]);
return len;
}
/**
* Printf-like functionality for the kernel.
*
* %% - print '%',
* %c - character,
* %s - string,
* %d, %u - decimal integer,
* %x, %X - hex integer,
*/
int kprintf(const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = kvprintf(fmt, ap);
va_end(ap);
return ret;
}
int kvprintf(const char *fmt, va_list ap) {
int ret = mini_vpprintf(stdout_puts, NULL, fmt, ap);
return ret;
}

View file

@ -1,20 +0,0 @@
#ifndef STDIO_H
#define STDIO_H
#include <stdarg.h>
int kprintf(const char *restrict format, ...);
int kvprintf(const char *fmt, va_list ap);
// int fprintf(FILE *restrict stream, const char *restrict format, ...);
// int dprintf(int fd, const char *restrict format, ...);
// int sprintf(char *restrict str, const char *restrict format, ...);
// int snprintf(char str[restrict.size], size_t size, const char *restrict format, ...);
// int vprintf(const char *restrict format, va_list ap);
// int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap);
// int vdprintf(int fd, const char *restrict format, va_list ap);
// int vsprintf(char *restrict str, const char *restrict format, va_list ap);
// int vsnprintf(char str[restrict.size], size_t size, const char *restrict format, va_list ap);
#endif // STDIO_H

View file

@ -1,13 +0,0 @@
#include <stdlib.h>
int abs(int a) {
return a > 0 ? a : -a;
}
long labs(long a) {
return a > 0 ? a : -a;
}
long long llabs(long long a) {
return a > 0 ? a : -a;
}

View file

@ -1,11 +0,0 @@
#ifndef STDLIB_H
#define STDLIB_H
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
int abs(int);
long labs(long);
long long llabs(long long);
#endif // STDLIB_H

View file

@ -114,6 +114,18 @@ void *memset(void *dest, int c, size_t n) {
return dest;
}
// int memcmp(const void *s1, const void *s2, size_t n) {
// if (n != 0) {
// const unsigned char *p1 = s1, *p2 = s2;
//
// do {
// if (*p1++ != *p2++)
// return (*--p1 - *--p2);
// } while (--n != 0);
// }
// return (0);
// }
char *itoa(int value, char *str, int base) {
char *p = str;
char *p1, *p2;
@ -154,6 +166,39 @@ char *itoa(int value, char *str, int base) {
return str;
}
// void *memset(void *dst, int c, size_t length) {
// u8 *ptr = (u8 *)dst;
// const u8 value = (u8)c;
//
// while (length--) *(ptr++) = value;
//
// return dst;
// }
// void *memcpy(void *dst, const void *src, size_t len) {
// u8 *d = (u8 *)dst;
// const u8 *s = (const u8 *)src;
// for (size_t i = 0; i < len; i++) {
// d[i] = s[i];
// }
// return dst;
// }
// void *memmove(void *dst, const void *src, size_t len) {
// u8 *d = (u8 *)dst;
// const u8 *s = (const u8 *)src;
// if (d < s) {
// for (size_t i = 0; i < len; i++) {
// d[i] = s[i];
// }
// } else if (d > s) {
// for (size_t i = len; i > 0; i--) {
// d[i - 1] = s[i - 1];
// }
// }
// return dst;
// }
int memcmp(const void *s1, const void *s2, size_t len) {
const u8 *a = (const u8 *)s1;
const u8 *b = (const u8 *)s2;
@ -178,20 +223,3 @@ size_t strnlen(const char *s, size_t maxlen) {
}
return len;
}
int strncmp(const char *p, const char *q, u32 n) {
while (n > 0 && *p && *p == *q) n--, p++, q++;
if (n == 0)
return 0;
return (u8)*p - (u8)*q;
}
char *strncpy(char *s, const char *t, int n) {
char *os;
os = s;
while (n-- > 0 && (*s++ = *t++) != 0) {
}
while (n-- > 0) *s++ = 0;
return os;
}

View file

@ -2,7 +2,6 @@
#define KERNEL_STRING_H
#include <stdint.h>
#include <stdlib.h>
// void *memcpy(void *s1, const void *s2, size_t n);
// void *memmove(void *s1, const void *s2, size_t n);
@ -31,17 +30,16 @@ size_t strlen(const char *s);
/** Return length of string `s`, up to a max of `maxlen` bytes */
size_t strnlen(const char *s, size_t maxlen);
int strncmp(const char *p, const char *q, u32 n);
char *strncpy(char *s, const char *t, int n);
// TODO: These:
/*
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strcpy(char *dst, const char *src);
char *strncpy(char *dst, const char *src, size_t n);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
*/
#endif // KERNEL_STRING_H
#endif

View file

@ -1,6 +1,8 @@
/* QEMU memory maps a UART device here. */
#define UART_BASE ((volatile char *)0x10000000)
void uart_putc(char c) {
*UART_BASE = c;
void uart_putc(char c) { *UART_BASE = c; }
void uart_puts(const char *s) {
while (*s) uart_putc(*s++);
}

View file

@ -4,4 +4,7 @@
/** Send a single character to the UART device */
void uart_putc(char c);
#endif // UART_KERNEL_H
/** Send a **NULL TERMINATED** string to the UART device */
void uart_puts(const char *s);
#endif

View file

@ -1,28 +0,0 @@
#ifndef UTIL_H
#define UTIL_H
/*
* Give hints to the compiler for branch prediction optimization.
*/
#include <stdint.h>
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 2))
#define likely(c) (__builtin_expect(!!(c), 1))
#define unlikely(c) (__builtin_expect(!!(c), 0))
#else
#define likely(c) (c)
#define unlikely(c) (c)
#endif
/* Round up to nearest power of two */
static inline uint32_t next_power_of_two(uint32_t v) {
/* See: https://graphics.stanford.edu/%7Eseander/bithacks.html#RoundUpPowerOf2 */
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return ++v;
}
#endif // UTIL_H

View file

@ -1,7 +1,5 @@
#ifndef PROC_H
#define PROC_H
#include <config.h>
#include <spinlock.h>
#include <riscv.h>
#include <stdint.h>
@ -15,7 +13,7 @@ typedef enum {
} ProcessState;
/** Saved registers for kernel context switches. */
typedef struct Context {
struct Context {
uint64_t ra;
uint64_t sp;
@ -32,18 +30,18 @@ typedef struct Context {
uint64_t s9;
uint64_t s10;
uint64_t s11;
} Context;
};
/** Per-CPU state. */
typedef struct cpu_t {
struct Cpu {
struct Process *proc; // The process running on this cpu, or null.
struct Context context; // swtch() here to enter scheduler().
int noff; // Depth of push_off() nesting.
int intena; // Were interrupts enabled before push_off()?
} Cpu;
};
/** Saved registers for kernel context switches. */
typedef struct TrapFrame_t {
typedef struct {
/* 0 */ uint64_t kernel_satp; // kernel page table
/* 8 */ uint64_t kernel_sp; // top of process's kernel stack
/* 16 */ uint64_t kernel_trap; // usertrap()
@ -80,13 +78,11 @@ typedef struct TrapFrame_t {
/* 264 */ uint64_t t4;
/* 272 */ uint64_t t5;
/* 280 */ uint64_t t6;
} TrapFrame;
} TrapFrame_t;
Cpu *mycpu(void);
struct Cpu *mycpu(void);
extern Cpu cpus[NCPU];
extern struct Cpu cpus[NCPU];
/** Per-process state */
struct Proc {};
#endif // PROC_H

View file

@ -1,121 +0,0 @@
#ifndef SLAB_H
#define SLAB_H
/*
* To understand this code, some prerequisite knowledge on memory and allocators are
* required. You should probably know what a free-list is, and maybe how to implement a bump allocator.
*
* See James Shackleford's excellent presentation on the Linux slab allocator:
* https://www.youtube.com/watch?v=pFi-JKgoX-I
*
* In the Linux source tree, the slub implementation resides in:
* mm/slub.c
*
* To see the slab caches on a linux system:
* $ sudo cat /proc/slabinfo
* In order of columns:
* name, active obj, total n obj, obj size, obj per slab, pages per slab
* For more info about how to decode this, see:
* $ man 5 slabinfo
*
* The way kernel memory allocation works in modern unixes is essentially outlined by:
* kmalloc() -> slub/slab/slob -> binary-buddy
*
* Where kmalloc redirects the requests to one of its appropriately sized slab caches,
* which in turn checks for an available cache, and if not found, allocates a new one
* using the binary-buddy allocator, which only allocates fixed size objects (usually pages)
*/
#include <stddef.h>
#include <stdint.h>
#define KERN_TOP_ADDR
#define USER_TOP_ADDR
#define POISON_FREE 0x6b
#define POISON_END 0x6a
#define POISON_IN_USE 0x5a
#define RED_INACTIVE 0xbb
#define RED_ACTIVE 0xcc
/* Canonical addresses are addresses that point to unmapped memory (neither user nor kernel space) */
#define IS_CANONICAL_ADDRESS(ptr) (ptr < KERN_TOP_ADDR && ptr > USER_TOP_ADDR)
/* 'bin size', 'order' */
#define SIZE_TO_KMALLOC_CACHE_INDEX(size) (0)
struct kmem_cache *kmalloc_caches[10];
/* GetFreePages_t: The type used for flags in various allocation related functions */
typedef uint32_t gfp_t;
/* Kmalloc manages an internal array of slab caches, sizes 8 bytes to 2^13 bytes */
void *kzalloc(size_t size); // Same but zeroes memory
void *kmalloc(size_t size) {
/* If the order (size) is too large to fit inside one of the slab caches, go directly to frame (page, buddy)
* allocator */
struct kmem_cache *suitable_cache = kmalloc_caches[SIZE_TO_KMALLOC_CACHE_INDEX(size)];
/* Do operations on kmem cache */
(void)suitable_cache;
return NULL;
}
/* For big allocations, not physically contiguous */
void *vmalloc(size_t size);
// SLAB_HWCACHE_ALIGN
// SLAB_CACHE_DMA
// SLAB_PANIC
/* This struct exists only conceptually, as the poison is variable in length */
/* The struct within each slab */
struct kmem_free_obj {
/* FreePointer, pointer to the next free pointer in the slab, if null then full, essentially a linked list */
/* Poison, inserted to see if someone reads or writes to a free area, checked by comparison, these values are known
*/
/* Pad, to keep things aligned*/
};
/* This struct exists only conceptually */
struct kmem_allocated_obj {
char payload[128]; /* Sized for demonstration */
char red_zone[16]; /* Sized for demonstration */
};
/* Per cpu slab cache, to avoid worrying about locking */
struct kmem_cache_cpu {
/* FreeList, points to the _first free object_, which will be equal to the Page pointer if the page is empty */
/* Page, the page allocated by buddy */
/* Page_amt, there may be multiple pages */
};
/* Essentially a list head for pages */
struct kmem_page {
/* Page */
/* FirstFree */
/* Slabsize? */
/* Next */
/* Prev? */
};
/* Global (as in cross CPU) pointers to pages in various states */
/* When kmem_cache_cpu->page gets full, it gets swapped into the full linked list */
/* Operations on this struct requires locking */
struct kmem_cache_node {
/* Partial, linked list of kmem_page, moved from full once something inside a full page is free'd */
/* Full, linked list of kmem_page */
};
struct kmem_cache {
const char *name;
struct kmem_cache_cpu *cpu_slab;
struct kmem_cache_node *node;
};
// KMEM_CACHE macro
// kmem_cache_create(name, size, alignment, flags, constructor)
// kmem_cache_destroy(*kmem_cache)
// kmem_cache_alloc(*kmem_cache, flags (GFP_KERNEL|GFP_ATOMIC|GFP_ZERO))
// kmem_cache_free(*kmem_cache, *obj) <- Optionally checks redzone
#endif // SLAB_H

View file

@ -1,13 +1,14 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _entry ) /* See: entry.S */
MEMORY
{
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 128M
}
SECTIONS
{
/*
* ensure that entry.S / _entry is at 0x80000000,
* where qemu's -kernel jumps.
*/
. = 0x80000000;
/*
* This section contains the code. This is, the machine language instructions
* that will be executed by the processor. In here we will find symbols
@ -34,7 +35,7 @@ SECTIONS
/* Define symbol etext to be the current location. */
PROVIDE(etext = .);
} > RAM :text
} :text
/*
* This contains any data that is marked as read only.
@ -46,7 +47,7 @@ SECTIONS
*(.srodata*) /* do not need to distinguish this from .rodata */
. = ALIGN(16);
*(.rodata*)
} > RAM
}
/*
* This section contains initialized global and static variables.
@ -57,7 +58,7 @@ SECTIONS
*(.sdata*) /* do not need to distinguish this from .data */
. = ALIGN(16);
*(.data*)
} > RAM
}
/*
* Contains all uninitialized global and static var iables. These are usually
@ -70,12 +71,10 @@ SECTIONS
*(.sbss*) /* do not need to distinguish this from .bss */
. = ALIGN(16);
*(.bss*)
} > RAM
}
/* Define symbol end as current location, note that this is not aligned, see vm.c */
PROVIDE(kernel_end = .);
PROVIDE(__heap_start = ALIGN(32));
PROVIDE(__heap_end = ORIGIN(RAM) + LENGTH(RAM));
}
PHDRS {

View file

@ -1,26 +0,0 @@
The Minimal snprintf() implementation
Copyright (c) 2013 Michal Ludvig <michal@logix.cz>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the auhor nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,173 +0,0 @@
Monocypher as a whole is dual-licensed. Choose whichever licence you
want from the two licences listed below.
The first licence is a regular 2-clause BSD licence. The second licence
is the CC-0 from Creative Commons. It is intended to release Monocypher
to the public domain. The BSD licence serves as a fallback option.
See the individual files for specific information about who contributed
to what file during which years. See below for special notes.
Licence 1 (2-clause BSD)
------------------------
Copyright (c) 2017-2023, Loup Vaillant
Copyright (c) 2017-2019, Michael Savage
Copyright (c) 2017-2023, Fabio Scotoni
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Licence 2 (CC-0)
----------------
> CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
> LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
> ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
> INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
> REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
> PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
> THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
> HEREUNDER.
### Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work
of authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without
fear of later claims of infringement build upon, modify, incorporate in
other works, reuse and redistribute as freely as possible in any form
whatsoever and for any purposes, including without limitation commercial
purposes. These owners may contribute to the Commons to promote the
ideal of a free culture and the further production of creative, cultural
and scientific works, or to gain reputation or greater distribution for
their Work in part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or
she is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under
its terms, with knowledge of his or her Copyright and Related Rights in
the Work and the meaning and intended legal effect of CC0 on those
rights.
1. **Copyright and Related Rights.** A Work made available under CC0 may
be protected by copyright and related or neighboring rights
("Copyright and Related Rights"). Copyright and Related Rights
include, but are not limited to, the following:
- the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
- moral rights retained by the original author(s) and/or
performer(s); publicity and privacy rights pertaining to a person's
image or likeness depicted in a Work;
- rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
- rights protecting the extraction, dissemination, use and reuse of
data in a Work;
- database rights (such as those arising under Directive 96/9/EC of
the European Parliament and of the Council of 11 March 1996 on the
legal protection of databases, and under any national
implementation thereof, including any amended or successor version
of such directive); and
- other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. **Waiver.** To the greatest extent permitted by, but not in
contravention of, applicable law, Affirmer hereby overtly, fully,
permanently, irrevocably and unconditionally waives, abandons, and
surrenders all of Affirmer's Copyright and Related Rights and
associated claims and causes of action, whether now known or unknown
(including existing as well as future claims and causes of action),
in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"Waiver"). Affirmer makes the Waiver for the benefit of each member
of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal
or equitable action to disrupt the quiet enjoyment of the Work by the
public as contemplated by Affirmer's express Statement of Purpose.
3. **Public License Fallback.** Should any part of the Waiver for any
reason be judged legally invalid or ineffective under applicable law,
then the Waiver shall be preserved to the maximum extent permitted
taking into account Affirmer's express Statement of Purpose. In
addition, to the extent the Waiver is so judged Affirmer hereby
grants to each affected person a royalty-free, non transferable, non
sublicensable, non exclusive, irrevocable and unconditional license
to exercise Affirmer's Copyright and Related Rights in the Work (i)
in all territories worldwide, (ii) for the maximum duration provided
by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and
(iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "License"). The
License shall be deemed effective as of the date CC0 was applied by
Affirmer to the Work. Should any part of the License for any reason
be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the
remainder of the License, and in such case Affirmer hereby affirms
that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any
associated claims and causes of action with respect to the Work, in
either case contrary to Affirmer's express Statement of Purpose.
4. **Limitations and Disclaimers.**
- No trademark or patent rights held by Affirmer are waived,
abandoned, surrendered, licensed or otherwise affected by this
document.
- Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy,
or the present or absence of errors, whether or not discoverable,
all to the greatest extent permissible under applicable law.
- Affirmer disclaims responsibility for clearing rights of other
persons that may apply to the Work or any use thereof, including
without limitation any person's Copyright and Related Rights in the
Work. Further, Affirmer disclaims responsibility for obtaining any
necessary consents, permissions or other rights required for any
use of the Work.
- Affirmer understands and acknowledges that Creative Commons is not
a party to this document and has no duty or obligation with respect
to this CC0 or use of the Work.
Special notes
-------------
The files in `tests/externals/` were placed in the public domain by
their respective authors. See the `AUTHORS.md` files in each directory.

View file

@ -1,193 +0,0 @@
musl as a whole is licensed under the following standard MIT license:
----------------------------------------------------------------------
Copyright © 2005-2020 Rich Felker, et al.
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.
----------------------------------------------------------------------
Authors/contributors include:
A. Wilcox
Ada Worcester
Alex Dowad
Alex Suykov
Alexander Monakov
Andre McCurdy
Andrew Kelley
Anthony G. Basile
Aric Belsito
Arvid Picciani
Bartosz Brachaczek
Benjamin Peterson
Bobby Bingham
Boris Brezillon
Brent Cook
Chris Spiegel
Clément Vasseur
Daniel Micay
Daniel Sabogal
Daurnimator
David Carlier
David Edelsohn
Denys Vlasenko
Dmitry Ivanov
Dmitry V. Levin
Drew DeVault
Emil Renner Berthing
Fangrui Song
Felix Fietkau
Felix Janda
Gianluca Anzolin
Hauke Mehrtens
He X
Hiltjo Posthuma
Isaac Dunham
Jaydeep Patil
Jens Gustedt
Jeremy Huntwork
Jo-Philipp Wich
Joakim Sindholt
John Spencer
Julien Ramseier
Justin Cormack
Kaarle Ritvanen
Khem Raj
Kylie McClain
Leah Neukirchen
Luca Barbato
Luka Perkov
Lynn Ochs
M Farkas-Dyck (Strake)
Mahesh Bodapati
Markus Wichmann
Masanori Ogino
Michael Clark
Michael Forney
Mikhail Kremnyov
Natanael Copa
Nicholas J. Kain
orc
Pascal Cuoq
Patrick Oppenlander
Petr Hosek
Petr Skocik
Pierre Carrier
Reini Urban
Rich Felker
Richard Pennington
Ryan Fairfax
Samuel Holland
Segev Finer
Shiz
sin
Solar Designer
Stefan Kristiansson
Stefan O'Rear
Szabolcs Nagy
Timo Teräs
Trutz Behn
Will Dietz
William Haddon
William Pitcock
Portions of this software are derived from third-party works licensed
under terms compatible with the above MIT license:
The TRE regular expression implementation (src/regex/reg* and
src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
under a 2-clause BSD license (license text in the source files). The
included version has been heavily modified by Rich Felker in 2012, in
the interests of size, simplicity, and namespace cleanliness.
Much of the math library code (src/math/* and src/complex/*) is
Copyright © 1993,2004 Sun Microsystems or
Copyright © 2003-2011 David Schultz or
Copyright © 2003-2009 Steven G. Kargl or
Copyright © 2003-2009 Bruce D. Evans or
Copyright © 2008 Stephen L. Moshier or
Copyright © 2017-2018 Arm Limited
and labelled as such in comments in the individual source files. All
have been licensed under extremely permissive terms.
The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008
The Android Open Source Project and is licensed under a two-clause BSD
license. It was taken from Bionic libc, used on Android.
The AArch64 memcpy and memset code (src/string/aarch64/*) are
Copyright © 1999-2019, Arm Limited.
The implementation of DES for crypt (src/crypt/crypt_des.c) is
Copyright © 1994 David Burren. It is licensed under a BSD license.
The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was
originally written by Solar Designer and placed into the public
domain. The code also comes with a fallback permissive license for use
in jurisdictions that may not recognize the public domain.
The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
Lynn Ochs and is licensed under an MIT-style license.
The x86_64 port was written by Nicholas J. Kain and is licensed under
the standard MIT terms.
The mips and microblaze ports were originally written by Richard
Pennington for use in the ellcc project. The original code was adapted
by Rich Felker for build system and code conventions during upstream
integration. It is licensed under the standard MIT terms.
The mips64 port was contributed by Imagination Technologies and is
licensed under the standard MIT terms.
The powerpc port was also originally written by Richard Pennington,
and later supplemented and integrated by John Spencer. It is licensed
under the standard MIT terms.
All other files which have no copyright comments are original works
produced specifically for use as part of this library, written either
by Rich Felker, the main author of the library, or by one or more
contibutors listed above. Details on authorship of individual files
can be found in the git version control history of the project. The
omission of copyright and license comments in each file is in the
interest of source tree size.
In addition, permission is hereby granted for all public header files
(include/* and arch/*/bits/*) and crt files intended to be linked into
applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit
the copyright notice and permission notice otherwise required by the
license, and to use these files without any requirement of
attribution. These files include substantial contributions from:
Bobby Bingham
John Spencer
Nicholas J. Kain
Rich Felker
Richard Pennington
Stefan Kristiansson
Szabolcs Nagy
all of whom have explicitly granted such permission.
This file previously contained text expressing a belief that most of
the files covered by the above exception were sufficiently trivial not
to be subject to copyright, resulting in confusion over whether it
negated the permissions granted in the license. In the spirit of
permissive licensing, and of not having licensing issues being an
obstacle to adoption, that text has been removed.

View file

@ -1,23 +0,0 @@
The xv6 software is:
Copyright (c) 2006-2024 Frans Kaashoek, Robert Morris, Russ Cox,
Massachusetts Institute of Technology
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.

View file

@ -1,15 +1,10 @@
#include <assert.h>
#include <banner.h>
#include <buddy.h>
#include <config.h>
#include <ispinlock.h>
#include <kalloc.h>
#include <memory.h>
#include <panic.h>
#include <proc.h>
#include <riscv.h>
#include <spinlock.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <uart.h>
/**
@ -41,26 +36,31 @@ void start() {
if (id == 0) {
/* Here we will do a bunch of initialization steps */
memory_sweep(heap_start, heap_end);
buddy_init(heap_start, heap_end);
kalloc_init();
uart_puts("Hello Neptune!\n");
spinlock_init(&sl);
for (int i = 0; i < banner_len; i++) uart_putc(banner[i]);
__sync_synchronize();
hold = 0;
} else {
while (hold);
}
// spin_lock(&sl);
//
// uart_puts("Hart number: ");
// uart_putc(id + '0');
// uart_putc('\n');
//
// spin_unlock(&sl);
if (id == 0) {
spin_lock(&sl);
kprintf("Core count: %d\n", max_hart);
if (max_hart == NCPU)
kprintf("All cores up!\n");
else
PANIC("Some cores seem to have been enumerated incorrectly!\n");
kprintf("To exit qemu, press CTRL+a followed by x\n");
uart_puts("Core count: ");
uart_putc(max_hart + '0');
uart_putc('\n');
if (max_hart == NCPU) {
uart_puts("All cores up!");
uart_putc('\n');
}
spin_unlock(&sl);
}