Compare commits
84 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c72bce50ac | ||
![]() |
700828676b | ||
![]() |
6b12606d82 | ||
![]() |
6cb84f5081 | ||
![]() |
ca0b25d110 | ||
![]() |
d583dbaced | ||
![]() |
f01b71f4a6 | ||
![]() |
45ad16efb0 | ||
![]() |
e9f2eef252 | ||
![]() |
8316c9f6ae | ||
![]() |
90c63ab41e | ||
![]() |
21d55031d9 | ||
![]() |
e762502c33 | ||
![]() |
7301205e1f | ||
![]() |
57be90da84 | ||
![]() |
6f5746a805 | ||
![]() |
89197a0b07 | ||
![]() |
dac4f9de43 | ||
![]() |
bb38272597 | ||
![]() |
aff745ab63 | ||
![]() |
f9b72df529 | ||
![]() |
2eba11bb3f | ||
![]() |
9bd5fdfa45 | ||
![]() |
291d0797e3 | ||
![]() |
851424f3cb | ||
![]() |
b9b1de5ff1 | ||
![]() |
78e4ad9885 | ||
![]() |
129b29eaf3 | ||
![]() |
4ee23cd145 | ||
![]() |
c82f60c685 | ||
![]() |
e5d5ad5c2e | ||
![]() |
17e8021a43 | ||
![]() |
a02c1fcebd | ||
![]() |
e15b705eda | ||
![]() |
595ae0a8e2 | ||
![]() |
f98500001c | ||
![]() |
c38a0cbf41 | ||
![]() |
4ed3650089 | ||
![]() |
8d126a6dfd | ||
![]() |
e27517f523 | ||
![]() |
9fd79ba46e | ||
![]() |
f52f670eca | ||
![]() |
6bbaec0294 | ||
![]() |
0e598b7ee0 | ||
![]() |
9790807355 | ||
![]() |
8839f06fd2 | ||
![]() |
7ba7b9cc63 | ||
![]() |
68f3353fbd | ||
![]() |
5596841482 | ||
![]() |
e30cc4c3d0 | ||
![]() |
ee6c75d905 | ||
![]() |
f5a32db7a3 | ||
![]() |
d15ab5cc04 | ||
![]() |
59fda90b89 | ||
![]() |
4c96aac02c | ||
![]() |
edc082adcb | ||
![]() |
f654aeb038 | ||
![]() |
73795f8944 | ||
![]() |
6a6068c8b6 | ||
![]() |
f2c4a3ed28 | ||
![]() |
0d8a1af1ff | ||
![]() |
6c21ac7669 | ||
![]() |
a6ae43f583 | ||
![]() |
7018424278 | ||
![]() |
a1f592c880 | ||
![]() |
0df09d5086 | ||
![]() |
eec052bafa | ||
![]() |
52f88785c4 | ||
![]() |
23a41dfbdd | ||
![]() |
c8abe9e1aa | ||
![]() |
b24035c51f | ||
![]() |
ca844d89e4 | ||
![]() |
1c279c9d4d | ||
![]() |
4bb015745a | ||
![]() |
f1fd7de79f | ||
![]() |
3450ab2cb8 | ||
![]() |
3a476fa195 | ||
![]() |
85ffed0c20 | ||
![]() |
c1a2c75054 | ||
![]() |
b9f3a25595 | ||
![]() |
438f85dc79 | ||
![]() |
a79af996e1 | ||
![]() |
f28082f98f | ||
![]() |
c52e19de83 |
51 changed files with 1860 additions and 855 deletions
4
.clang-format-ignore
Normal file
4
.clang-format-ignore
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
**/mini-printf.c
|
||||||
|
**/mini-printf.h
|
||||||
|
**/monocypher.c
|
||||||
|
**/monocypher.h
|
153
Makefile
153
Makefile
|
@ -1,6 +1,19 @@
|
||||||
# TOOLPREFIX = riscv64-linux-gnu
|
# See: https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases
|
||||||
# TOOLPREFIX = toolchain/xpack-riscv-none-elf-gcc-14.2.0-3/bin/riscv-none-elf
|
# See: https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases
|
||||||
TOOLPREFIX = toolchain/gcc/bin/riscv-none-elf
|
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
|
||||||
|
|
||||||
CC = $(TOOLPREFIX)-gcc
|
CC = $(TOOLPREFIX)-gcc
|
||||||
AS = $(TOOLPREFIX)-as
|
AS = $(TOOLPREFIX)-as
|
||||||
|
@ -10,14 +23,18 @@ OBJDUMP = $(TOOLPREFIX)-objdump
|
||||||
|
|
||||||
ASFLAGS = -march=rv64gc -mabi=lp64
|
ASFLAGS = -march=rv64gc -mabi=lp64
|
||||||
|
|
||||||
LDFLAGS = -Tkernel.ld
|
LDFLAGS = -Tkern/kernel.ld
|
||||||
LDFLAGS += -m elf64lriscv
|
LDFLAGS += -m elf64lriscv
|
||||||
|
|
||||||
CFLAGS = -Wall -Werror -O
|
CFLAGS = -Wall -Werror -O
|
||||||
CFLAGS += -Wno-unused-result
|
CFLAGS += -Wno-unused-result
|
||||||
CFLAGS += -mcmodel=medany
|
CFLAGS += -mcmodel=medany
|
||||||
CFLAGS += -march=rv64gc -mabi=lp64
|
CFLAGS += -march=rv64gc -mabi=lp64
|
||||||
CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
|
CFLAGS += -ffreestanding
|
||||||
|
CFLAGS += -fno-common
|
||||||
|
CFLAGS += -nostdlib
|
||||||
|
CFLAGS += -mno-relax
|
||||||
|
CFLAGS += -std=gnu99
|
||||||
|
|
||||||
CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support
|
CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support
|
||||||
CFLAGS += -MD # Generate header dependency files (.d)
|
CFLAGS += -MD # Generate header dependency files (.d)
|
||||||
|
@ -25,93 +42,113 @@ CFLAGS += -fno-pie -no-pie # Fixed address linking
|
||||||
CFLAGS += -ggdb -gdwarf-2 # GDB debug info
|
CFLAGS += -ggdb -gdwarf-2 # GDB debug info
|
||||||
CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB
|
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.
|
||||||
CFLAGS += -Ilib
|
CFLAGS += -I./kern
|
||||||
|
CFLAGS += -I./kern/libkern
|
||||||
|
|
||||||
all: kernel.elf
|
all: kern/kernel.elf
|
||||||
|
build: all
|
||||||
|
|
||||||
main: main.o
|
quickstart:
|
||||||
|
make get_toolchain && bear -- make -j$(nproc) && make qemu
|
||||||
|
|
||||||
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
|
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)
|
||||||
@echo LD $@
|
@echo LD $@
|
||||||
@$(LD) $(LDFLAGS) -o $@ $^
|
@$(LD) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
@echo CC $@
|
@echo CC $@
|
||||||
@$(CC) $(KCFLAGS) -nostdinc -I. -c $< -o $@
|
@$(CC) $(CFLAGS) -nostdinc -I. -c $< -o $@
|
||||||
|
|
||||||
%.o: %.S
|
%.o: %.S
|
||||||
@echo AS $@
|
@echo AS $@
|
||||||
@$(AS) $(ASFLAGS) -o $@ $<
|
@$(AS) $(ASFLAGS) -o $@ $<
|
||||||
|
|
||||||
qemu: kernel.elf
|
qemu: kern/kernel.elf
|
||||||
@echo QEMU $<
|
@echo QEMU $<
|
||||||
@qemu-system-riscv64 -machine virt -bios none -nographic -m 128M -smp 4 -kernel kernel.elf
|
@$(QEMU) -machine virt -bios none -nographic -m 128M -smp 4 -kernel $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.elf *.d lib/*.o lib/*.d
|
find . -type f -name '*.[od(elf)]' -exec rm -f {} +
|
||||||
fd -e o -x rm # TODO: Should only depend on posix
|
|
||||||
|
|
||||||
-include *.d
|
format:
|
||||||
|
find kern -type f -name '*.[ch]' -exec clang-format -i {} \;
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
help:
|
||||||
# Toolchain configuration
|
@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_DIR := toolchain
|
TOOLCHAIN_DIR := toolchain
|
||||||
|
|
||||||
# Versions
|
QEMU_TARBALL := xpack-qemu-riscv-$(QEMU_VER)-linux-x64.tar.gz
|
||||||
QEMU_VER := 8.2.6-1
|
GCC_TARBALL := xpack-riscv-none-elf-gcc-$(GCC_VER)-linux-x64.tar.gz
|
||||||
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)
|
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)
|
GCC_URL := https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v$(GCC_VER)/$(GCC_TARBALL)
|
||||||
|
|
||||||
# Paths
|
QEMU_TARPATH := toolchain/$(QEMU_TARBALL)
|
||||||
QEMU_TARPATH := toolchain/xpack-qemu-riscv-8.2.6-1-linux-arm.tar.gz
|
GCC_TARPATH := toolchain/$(GCC_TARBALL)
|
||||||
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)
|
QEMU_SYM_DIR := xpack-qemu-riscv-$(QEMU_VER)
|
||||||
GCC_SYM_DIR := xpack-riscv-none-elf-gcc-$(GCC_VER)
|
GCC_SYM_DIR := xpack-riscv-none-elf-gcc-$(GCC_VER)
|
||||||
|
|
||||||
# Final symlink/alias
|
$(TOOLCHAIN_DIR):
|
||||||
GCC_ALIAS := gcc
|
@mkdir -p $@
|
||||||
QEMU_ALIAS := qemu
|
|
||||||
|
|
||||||
QEMU_TARPATH:
|
$(QEMU_TARPATH): $(TOOLCHAIN_DIR)
|
||||||
curl -# -L -o $@ $(QEMU_URL)
|
@echo "Fetching qemu-riscv-xpack: v$(QEMU_VER)"
|
||||||
|
@curl -# -L -o $@ $(QEMU_URL)
|
||||||
|
|
||||||
GCC_TARPATH:
|
$(GCC_TARPATH): $(TOOLCHAIN_DIR)
|
||||||
curl -# -L -o $@ $(GCC_URL)
|
@echo "Fetching riscv-none-elf-gcc-xpack: v$(GCC_VER)"
|
||||||
|
@curl -# -L -o $@ $(GCC_URL)
|
||||||
|
|
||||||
extractions:
|
get_toolchain: $(TOOLCHAIN_DIR) $(GCC_TARPATH) $(QEMU_TARPATH)
|
||||||
cd toolchain && tar xf $(QEMU_TARBALL)
|
@echo "Unpacking qemu..."
|
||||||
cd toolchain && tar xf $(GCC_TARBALL)
|
@cd toolchain && tar xf $(QEMU_TARBALL)
|
||||||
|
@echo "Unpacking gcc..."
|
||||||
toolchain: $(QEMU_TARPATH) $(GCC_TARPATH)
|
@cd toolchain && tar xf $(GCC_TARBALL)
|
||||||
mkdir -p toolchain
|
@cd $(TOOLCHAIN_DIR) && ln -sfn $(QEMU_SYM_DIR) qemu
|
||||||
cd toolchain && tar xf $(QEMU_TARBALL)
|
@cd $(TOOLCHAIN_DIR) && ln -sfn $(GCC_SYM_DIR) gcc
|
||||||
cd toolchain && tar xf $(GCC_TARBALL)
|
@echo "Toolchain in place, ready to make!"
|
||||||
cd $(TOOLCHAIN_DIR) && ln -sfn $(QEMU_SYM_DIR) $(QEMU_ALIAS)
|
|
||||||
cd $(TOOLCHAIN_DIR) && ln -sfn $(GCC_SYM_DIR) $(GCC_ALIAS)
|
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -rf $(TOOLCHAIN_DIR)
|
rm -rf $(TOOLCHAIN_DIR)
|
||||||
|
|
||||||
.PHONY: all toolchain
|
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
|
||||||
|
|
69
README.md
69
README.md
|
@ -5,7 +5,56 @@ Inspired by xv6
|
||||||
For a quick reference on RISC-V assembly:
|
For a quick reference on RISC-V assembly:
|
||||||
- https://risc-v.guru/instructions/
|
- https://risc-v.guru/instructions/
|
||||||
|
|
||||||
Toolchains:
|
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:
|
||||||
- https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
|
- https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
|
||||||
- https://github.com/xpack-dev-tools/qemu-riscv-xpack/
|
- https://github.com/xpack-dev-tools/qemu-riscv-xpack/
|
||||||
|
|
||||||
|
@ -15,6 +64,8 @@ Toolchains:
|
||||||
> term trap, largely because it was the term used by the PDP11/40 and therefore is the
|
> term trap, largely because it was the term used by the PDP11/40 and therefore is the
|
||||||
> conventional Unix term.
|
> conventional Unix term.
|
||||||
|
|
||||||
|
### Notes/Misc
|
||||||
|
|
||||||
| Register | Name | Privilege Level | Description |
|
| Register | Name | Privilege Level | Description |
|
||||||
|-------------|----------------------------|------------------|-----------------------------------------------------------------------------|
|
|-------------|----------------------------|------------------|-----------------------------------------------------------------------------|
|
||||||
| `mstatus` | Machine Status Register | Machine | Holds global interrupt enable, previous privilege mode, etc. |
|
| `mstatus` | Machine Status Register | Machine | Holds global interrupt enable, previous privilege mode, etc. |
|
||||||
|
@ -33,12 +84,18 @@ Toolchains:
|
||||||
| `mip` | Machine Interrupt Pending | Machine | Indicates pending interrupts. |
|
| `mip` | Machine Interrupt Pending | Machine | Indicates pending interrupts. |
|
||||||
| `mie` | Machine Interrupt Enable | Machine | Controls which interrupts are enabled. |
|
| `mie` | Machine Interrupt Enable | Machine | Controls which interrupts are enabled. |
|
||||||
|
|
||||||
# Notes
|
### 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
|
||||||
|
|
||||||
## Libc Implementations
|
### Libc Implementations
|
||||||
|
|
||||||
[uClibc](https://uclibc.org/)
|
- [Libc reference](https://discapes.github.io/libc-reference/)
|
||||||
[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)
|
[Comparison of C/POSIX standard library implementations for Linux](https://www.etalabs.net/compare_libcs.html) (by musl author)
|
||||||
|
|
3
config.h
3
config.h
|
@ -1,3 +1,5 @@
|
||||||
|
#ifndef KERNEL_CONFIG_H
|
||||||
|
#define KERNEL_CONFIG_H
|
||||||
/*
|
/*
|
||||||
* Number of CPU's For now, this is hard-coded here. It will likely be
|
* Number of CPU's For now, this is hard-coded here. It will likely be
|
||||||
* dynamically discovered in the future.
|
* dynamically discovered in the future.
|
||||||
|
@ -6,3 +8,4 @@
|
||||||
|
|
||||||
/* Maximum number of files open */
|
/* Maximum number of files open */
|
||||||
#define NOFILE 10
|
#define NOFILE 10
|
||||||
|
#endif // KERNEL_CONFIG_H
|
||||||
|
|
36
kern/banner.h
Normal file
36
kern/banner.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#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
|
|
@ -1,45 +0,0 @@
|
||||||
#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.
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#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);
|
|
|
@ -1,76 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
#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
|
|
|
@ -1,14 +1,13 @@
|
||||||
OUTPUT_ARCH( "riscv" )
|
OUTPUT_ARCH( "riscv" )
|
||||||
ENTRY( _entry ) /* See: entry.S */
|
ENTRY( _entry ) /* See: entry.S */
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 128M
|
||||||
|
}
|
||||||
|
|
||||||
SECTIONS
|
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
|
* This section contains the code. This is, the machine language instructions
|
||||||
* that will be executed by the processor. In here we will find symbols
|
* that will be executed by the processor. In here we will find symbols
|
||||||
|
@ -35,7 +34,7 @@ SECTIONS
|
||||||
|
|
||||||
/* Define symbol etext to be the current location. */
|
/* Define symbol etext to be the current location. */
|
||||||
PROVIDE(etext = .);
|
PROVIDE(etext = .);
|
||||||
} :text
|
} > RAM :text
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This contains any data that is marked as read only.
|
* This contains any data that is marked as read only.
|
||||||
|
@ -47,7 +46,7 @@ SECTIONS
|
||||||
*(.srodata*) /* do not need to distinguish this from .rodata */
|
*(.srodata*) /* do not need to distinguish this from .rodata */
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
}
|
} > RAM
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This section contains initialized global and static variables.
|
* This section contains initialized global and static variables.
|
||||||
|
@ -58,7 +57,7 @@ SECTIONS
|
||||||
*(.sdata*) /* do not need to distinguish this from .data */
|
*(.sdata*) /* do not need to distinguish this from .data */
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
*(.data*)
|
*(.data*)
|
||||||
}
|
} > RAM
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Contains all uninitialized global and static var iables. These are usually
|
* Contains all uninitialized global and static var iables. These are usually
|
||||||
|
@ -71,10 +70,12 @@ SECTIONS
|
||||||
*(.sbss*) /* do not need to distinguish this from .bss */
|
*(.sbss*) /* do not need to distinguish this from .bss */
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
*(.bss*)
|
*(.bss*)
|
||||||
}
|
} > RAM
|
||||||
|
|
||||||
/* Define symbol end as current location, note that this is not aligned, see vm.c */
|
/* Define symbol end as current location, note that this is not aligned, see vm.c */
|
||||||
PROVIDE(kernel_end = .);
|
PROVIDE(kernel_end = .);
|
||||||
|
PROVIDE(__heap_start = ALIGN(32));
|
||||||
|
PROVIDE(__heap_end = ORIGIN(RAM) + LENGTH(RAM));
|
||||||
}
|
}
|
||||||
|
|
||||||
PHDRS {
|
PHDRS {
|
103
kern/kprint.c
103
kern/kprint.c
|
@ -1,103 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
16
kern/libkern/assert.h
Normal file
16
kern/libkern/assert.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#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)
|
35
kern/libkern/badrand.c
Normal file
35
kern/libkern/badrand.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#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
|
43
kern/libkern/badrand.h
Normal file
43
kern/libkern/badrand.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#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
|
139
kern/libkern/buddy.c
Normal file
139
kern/libkern/buddy.c
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#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;
|
||||||
|
}
|
22
kern/libkern/buddy.h
Normal file
22
kern/libkern/buddy.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#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
|
|
@ -1,91 +1,136 @@
|
||||||
#ifndef ENDIAN_KERNEL_H
|
#ifndef ENDIAN_KERNEL_H
|
||||||
#define ENDIAN_KERNEL_H
|
#define ENDIAN_KERNEL_H
|
||||||
|
|
||||||
#include <types.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/** Swap byte order of 16-bit value */
|
/** 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 */
|
/** Swap byte order of 32-bit value */
|
||||||
static inline u32 swap32(u32 x) {
|
static inline u32 swap32(u32 x) {
|
||||||
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) |
|
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) | ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
||||||
((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Swap byte order of 64-bit value */
|
/** Swap byte order of 64-bit value */
|
||||||
static inline u64 swap64(u64 x) {
|
static inline u64 swap64(u64 x) {
|
||||||
return ((x >> 56) & 0x00000000000000ffULL) |
|
return ((x >> 56) & 0x00000000000000ffULL) | ((x >> 40) & 0x000000000000ff00ULL) |
|
||||||
((x >> 40) & 0x000000000000ff00ULL) |
|
((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 8) & 0x00000000ff000000ULL) |
|
||||||
((x >> 24) & 0x0000000000ff0000ULL) |
|
((x << 8) & 0x000000ff00000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) |
|
||||||
((x >> 8) & 0x00000000ff000000ULL) |
|
((x << 40) & 0x00ff000000000000ULL) | ((x << 56) & 0xff00000000000000ULL);
|
||||||
((x << 8) & 0x000000ff00000000ULL) |
|
|
||||||
((x << 24) & 0x0000ff0000000000ULL) |
|
|
||||||
((x << 40) & 0x00ff000000000000ULL) |
|
|
||||||
((x << 56) & 0xff00000000000000ULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __LITTLE_ENDIAN__
|
#ifdef __LITTLE_ENDIAN__
|
||||||
/** Convert 16-bit value to 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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
|
#else // Big-endian
|
||||||
|
|
||||||
/** Convert 16-bit value to little-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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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__
|
#endif // __LITTLE_ENDIAN__
|
||||||
|
|
||||||
|
|
139
kern/libkern/freelist.c
Normal file
139
kern/libkern/freelist.c
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#include "freelist.h"
|
||||||
|
|
||||||
|
/* Header block used to keep track of all the free blocks */
|
||||||
|
struct __attribute__((packed)) FreeListBlock {
|
||||||
|
uint16_t next_offset; /* May be 8, 16, 32, 64, whatever */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert pointer -> 1-based offset (0 means NULL) */
|
||||||
|
static inline uint32_t ptr_to_offset(FreeList *fl, void *ptr) {
|
||||||
|
if (!ptr)
|
||||||
|
return 0; // NULL maps to 0
|
||||||
|
uintptr_t diff = (uintptr_t)ptr - fl->start;
|
||||||
|
return (uint32_t)(diff / fl->size) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert 1-based offset -> pointer (0 means NULL) */
|
||||||
|
static inline void *offset_to_ptr(FreeList *fl, uint32_t offset) {
|
||||||
|
if (offset == 0)
|
||||||
|
return NULL; // 0 = invalid/null
|
||||||
|
return (void *)(fl->start + (uintptr_t)(offset - 1) * fl->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the FreeList */
|
||||||
|
int fl_init(FreeList *fl, uintptr_t start, size_t size_bytes, size_t itemsize) {
|
||||||
|
/* Fiddle around according to your need, (void *) alignment seems to be enough,
|
||||||
|
* but MAX_ALIGN_T is also an option. Especially for allocator implementation. */
|
||||||
|
size_t size = align_up_to(itemsize, sizeof(void *));
|
||||||
|
|
||||||
|
if (size < sizeof(FreeListBlock) || !fl)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fl->start = start;
|
||||||
|
fl->end = start + size_bytes;
|
||||||
|
fl->size = size;
|
||||||
|
fl->allocated = 0;
|
||||||
|
|
||||||
|
FreeListBlock *block = (FreeListBlock *)start;
|
||||||
|
|
||||||
|
for (size_t offset = 1; offset < fl_capacity(fl) + 1; offset++) {
|
||||||
|
block->next_offset = (int32_t)offset;
|
||||||
|
block = offset_to_ptr(fl, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
block->next_offset = 0; /* Last block */
|
||||||
|
fl->free = (FreeListBlock *)start;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate some memory from the FreeList */
|
||||||
|
void *fl_alloc(FreeList *fl) {
|
||||||
|
if (!fl->free)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
FreeListBlock *m = fl->free;
|
||||||
|
|
||||||
|
fl->free = offset_to_ptr(fl, fl->free->next_offset); /* May be null, which is fine */
|
||||||
|
fl->allocated++;
|
||||||
|
|
||||||
|
/* Wipe it before sending it out, could use memset
|
||||||
|
* here, or even wiping the entire block */
|
||||||
|
m->next_offset = 0;
|
||||||
|
|
||||||
|
/* For reference: */
|
||||||
|
// memset((void *)m, 0, fl->size); /* Wipe entire block */
|
||||||
|
// memset((void *)m, 0, sizeof(FreeListBlock)); /* Wipe only header */
|
||||||
|
|
||||||
|
return ((void *)m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return some memory to the FreeList */
|
||||||
|
int fl_free(FreeList *fl, void *ptr) {
|
||||||
|
if (!fl_is_managed(fl, ptr))
|
||||||
|
return 0; /* We cant free memory we do not own */
|
||||||
|
|
||||||
|
FreeListBlock *block = (FreeListBlock *)ptr;
|
||||||
|
|
||||||
|
block->next_offset = ptr_to_offset(fl, fl->free); /* May be null, which is fine */
|
||||||
|
fl->free = block;
|
||||||
|
fl->allocated--;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
uintptr_t p = (uintptr_t)ptr;
|
||||||
|
|
||||||
|
if (p < fl->start || p >= fl->end) {
|
||||||
|
return 0; // outside pool
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((p - fl->start) % fl->size) == 0; // aligned to block
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
avail++;
|
||||||
|
|
||||||
|
if (!fl_is_managed(fl, cursor) || avail > fl_capacity(fl))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (cursor->next_offset == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
cursor = offset_to_ptr(fl, cursor->next_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return avail;
|
||||||
|
}
|
28
kern/libkern/freelist.h
Normal file
28
kern/libkern/freelist.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef FREELIST_H
|
||||||
|
#define FREELIST_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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, size_t size_bytes, 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
|
|
@ -1,29 +1,21 @@
|
||||||
|
#include <assert.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <string.h>
|
#include <stdlib.h>
|
||||||
#include <uart.h>
|
|
||||||
|
|
||||||
#define MAX_PROBE_SIZE (256 * 1024 * 1024) // Probe up to 256 MiB max
|
int memory_sweep(const uintptr_t start, const uintptr_t end) {
|
||||||
#define PROBE_STEP 0x1000 // Probe every 4 KiB page
|
assert_msg(start < end, "Start needs to be before end.");
|
||||||
|
uintptr_t sweeper = start;
|
||||||
|
|
||||||
size_t probe_memory(void) {
|
while (sweeper < end) {
|
||||||
volatile u32 *addr;
|
*(uint64_t *)sweeper = 0xFAFAFAFABCBCBCBC;
|
||||||
u32 test_pattern = 0xA5A5A5A5;
|
sweeper += sizeof(uint64_t);
|
||||||
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
|
sweeper -= sizeof(uint64_t);
|
||||||
detected = offset + PROBE_STEP;
|
while (sweeper != start) {
|
||||||
|
assert(*(uint64_t *)sweeper == 0xFAFAFAFABCBCBCBC);
|
||||||
|
sweeper -= sizeof(uint64_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return detected;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,8 @@
|
||||||
#define PHYSTOP (KERNBASE + 128 * 1024 * 1024)
|
#define PHYSTOP (KERNBASE + 128 * 1024 * 1024)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns size in bytes of detected RAM In qemu, it requires a trap handler to
|
* Set and fetch routine for checking memory.
|
||||||
* handle the interrupt when accessing unavailable memory.
|
|
||||||
*/
|
*/
|
||||||
size_t probe_memory(void);
|
int memory_sweep(const uintptr_t start, const uintptr_t end);
|
||||||
|
|
||||||
#endif
|
#endif // MEMORY_KERNEL_H
|
||||||
|
|
|
@ -43,18 +43,13 @@
|
||||||
|
|
||||||
#include "mini-printf.h"
|
#include "mini-printf.h"
|
||||||
|
|
||||||
static int
|
static int mini_strlen(const char *s) {
|
||||||
mini_strlen(const char *s)
|
|
||||||
{
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
while (s[len] != '\0') len++;
|
while (s[len] != '\0') len++;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int mini_itoa(long value, unsigned int radix, int uppercase, int unsig, char *buffer) {
|
||||||
mini_itoa(long value, unsigned int radix, int uppercase, int unsig,
|
|
||||||
char *buffer)
|
|
||||||
{
|
|
||||||
char *pbuffer = buffer;
|
char *pbuffer = buffer;
|
||||||
int negative = 0;
|
int negative = 0;
|
||||||
int i, len;
|
int i, len;
|
||||||
|
@ -92,13 +87,12 @@ mini_itoa(long value, unsigned int radix, int uppercase, int unsig,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int mini_pad(char *ptr, int len, char pad_char, int pad_to, char *buffer) {
|
||||||
mini_pad(char* ptr, int len, char pad_char, int pad_to, char *buffer)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
int overflow = 0;
|
int overflow = 0;
|
||||||
char *pbuffer = buffer;
|
char *pbuffer = buffer;
|
||||||
if(pad_to == 0) pad_to = len;
|
if (pad_to == 0)
|
||||||
|
pad_to = len;
|
||||||
if (len > pad_to) {
|
if (len > pad_to) {
|
||||||
len = pad_to;
|
len = pad_to;
|
||||||
overflow = 1;
|
overflow = 1;
|
||||||
|
@ -123,10 +117,9 @@ struct mini_buff {
|
||||||
unsigned int buffer_len;
|
unsigned int buffer_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int _puts(char *s, int len, void *buf) {
|
||||||
_puts(char *s, int len, void *buf)
|
if (!buf)
|
||||||
{
|
return len;
|
||||||
if(!buf) return len;
|
|
||||||
struct mini_buff *b = buf;
|
struct mini_buff *b = buf;
|
||||||
char *p0 = b->buffer;
|
char *p0 = b->buffer;
|
||||||
int i;
|
int i;
|
||||||
|
@ -146,25 +139,21 @@ static int (*mini_handler) (void* data, void* obj, int ch, int lhint, char** bf)
|
||||||
static void (*mini_handler_freeor)(void *data, void *) = 0;
|
static void (*mini_handler_freeor)(void *data, void *) = 0;
|
||||||
static void *mini_handler_data = 0;
|
static void *mini_handler_data = 0;
|
||||||
|
|
||||||
void mini_printf_set_handler(
|
void mini_printf_set_handler(void *data, int (*handler)(void *data, void *obj, int ch, int len_hint, char **buf),
|
||||||
void* data,
|
void (*freeor)(void *data, void *buf)) {
|
||||||
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
|
|
||||||
void (*freeor)(void* data, void* buf))
|
|
||||||
{
|
|
||||||
mini_handler = handler;
|
mini_handler = handler;
|
||||||
mini_handler_freeor = freeor;
|
mini_handler_freeor = freeor;
|
||||||
mini_handler_data = data;
|
mini_handler_data = data;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va) {
|
||||||
mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va)
|
|
||||||
{
|
|
||||||
struct mini_buff b;
|
struct mini_buff b;
|
||||||
b.buffer = buffer;
|
b.buffer = buffer;
|
||||||
b.pbuffer = buffer;
|
b.pbuffer = buffer;
|
||||||
b.buffer_len = buffer_len;
|
b.buffer_len = buffer_len;
|
||||||
if(buffer_len == 0) buffer = (void*) 0;
|
if (buffer_len == 0)
|
||||||
|
buffer = (void *)0;
|
||||||
int n = mini_vpprintf(_puts, (buffer != (void *)0) ? &b : (void *)0, fmt, va);
|
int n = mini_vpprintf(_puts, (buffer != (void *)0) ? &b : (void *)0, fmt, va);
|
||||||
if (buffer == (void *)0) {
|
if (buffer == (void *)0) {
|
||||||
return n;
|
return n;
|
||||||
|
@ -172,9 +161,7 @@ mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list v
|
||||||
return b.pbuffer - b.buffer;
|
return b.pbuffer - b.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int mini_vpprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, va_list va) {
|
||||||
mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va)
|
|
||||||
{
|
|
||||||
char bf[24];
|
char bf[24];
|
||||||
char bf2[24];
|
char bf2[24];
|
||||||
char ch;
|
char ch;
|
||||||
|
@ -183,7 +170,8 @@ mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *f
|
||||||
#endif
|
#endif
|
||||||
if (puts == (void *)0) {
|
if (puts == (void *)0) {
|
||||||
/* run puts in counting mode. */
|
/* run puts in counting mode. */
|
||||||
puts = _puts; buf = (void*)0;
|
puts = _puts;
|
||||||
|
buf = (void *)0;
|
||||||
}
|
}
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while ((ch = *(fmt++))) {
|
while ((ch = *(fmt++))) {
|
||||||
|
@ -200,7 +188,8 @@ mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *f
|
||||||
ch = *(fmt++);
|
ch = *(fmt++);
|
||||||
|
|
||||||
/* Zero padding requested */
|
/* Zero padding requested */
|
||||||
if (ch == '0') pad_char = '0';
|
if (ch == '0')
|
||||||
|
pad_char = '0';
|
||||||
while (ch >= '0' && ch <= '9') {
|
while (ch >= '0' && ch <= '9') {
|
||||||
pad_to = pad_to * 10 + (ch - '0');
|
pad_to = pad_to * 10 + (ch - '0');
|
||||||
ch = *(fmt++);
|
ch = *(fmt++);
|
||||||
|
@ -214,8 +203,7 @@ mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *f
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 0:
|
case 0: goto end;
|
||||||
goto end;
|
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'd':
|
case 'd':
|
||||||
if (l) {
|
if (l) {
|
||||||
|
@ -284,10 +272,7 @@ end:
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mini_snprintf(char *buffer, unsigned int buffer_len, const char *fmt, ...) {
|
||||||
int
|
|
||||||
mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
int ret;
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
|
@ -297,9 +282,7 @@ mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int mini_pprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, ...) {
|
||||||
mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
int ret;
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
|
@ -308,4 +291,3 @@ mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __MINI_PRINTF__
|
#ifndef __MINI_PRINTF__
|
||||||
#define __MINI_PRINTF__
|
#define __MINI_PRINTF__
|
||||||
|
|
||||||
|
@ -42,8 +41,7 @@ extern "C" {
|
||||||
* void* arguments matching %O and %R are sent to handler as obj.
|
* void* arguments matching %O and %R are sent to handler as obj.
|
||||||
* the result string created by handler at *buf is freed by freeor.
|
* the result string created by handler at *buf is freed by freeor.
|
||||||
* */
|
* */
|
||||||
void mini_printf_set_handler(
|
void mini_printf_set_handler(void *data,
|
||||||
void * data,
|
|
||||||
/* handler returns number of chars in *buf; *buf is not NUL-terminated. */
|
/* 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),
|
int (*handler)(void *data, void *obj, int ch, int len_hint, char **buf),
|
||||||
void (*freeor)(void *data, void *buf));
|
void (*freeor)(void *data, void *buf));
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
|
#include "stdbool.h"
|
||||||
|
#include <mini-printf.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <uart.h>
|
#include <uart.h>
|
||||||
volatile int panicked;
|
|
||||||
|
|
||||||
void panic(char *s) {
|
volatile int panicked = false;
|
||||||
panicked = 1;
|
|
||||||
uart_puts(s);
|
__attribute__((visibility("hidden"))) void __panic(const char *restrict fmt, ...) {
|
||||||
while (1);
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
kvprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
panicked = true;
|
||||||
|
for (;;) asm volatile("wfi");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef KERNEL_PANIC_H
|
#ifndef KERNEL_PANIC_H
|
||||||
#define KERNEL_PANIC_H
|
#define KERNEL_PANIC_H
|
||||||
|
|
||||||
void panic(char *s);
|
#define PANIC(fmt, ...) __panic("[Panic @ %s:%d %s] " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
|
||||||
|
|
||||||
#endif
|
void __panic(const char *restrict fmt, ...);
|
||||||
|
|
||||||
|
#endif // KERNEL_PANIC_H
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <proc.h>
|
#include <proc.h>
|
||||||
|
|
||||||
struct Cpu cpus[NCPU];
|
Cpu cpus[NCPU];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Must be called with interrupts disabled, to prevent race with process being
|
* 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.
|
* Return this CPU's cpu struct. Interrupts must be disabled.
|
||||||
*/
|
*/
|
||||||
struct Cpu *mycpu(void) {
|
Cpu *mycpu(void) {
|
||||||
int id = cpuid();
|
int id = cpuid();
|
||||||
struct Cpu *c = &cpus[id];
|
Cpu *c = &cpus[id];
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,9 @@ static inline u64 read_tp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write thread pointer */
|
/** 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.
|
* Read the value of the sstatus register.
|
||||||
|
@ -60,10 +62,14 @@ static inline void w_sstatus(u64 x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Enable device interrupts */
|
/** 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 */
|
/** 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? */
|
/** Are device interrupts enabled? */
|
||||||
static inline int intr_get() {
|
static inline int intr_get() {
|
||||||
|
@ -71,4 +77,4 @@ static inline int intr_get() {
|
||||||
return (x & SSTATUS_SIE) != 0;
|
return (x & SSTATUS_SIE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // RISCV_KERNEL_H
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
* (Not mutexes as these are spinning locks).
|
* (Not mutexes as these are spinning locks).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// #include <lib/stdio.h>
|
#include "stddef.h"
|
||||||
#include "string.h"
|
|
||||||
#include <panic.h>
|
#include <panic.h>
|
||||||
#include <proc.h>
|
#include <proc.h>
|
||||||
#include <riscv.h>
|
#include <riscv.h>
|
||||||
|
@ -41,84 +40,95 @@
|
||||||
* On RISC-V, this emits a fence instruction.
|
* On RISC-V, this emits a fence instruction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Initialize Spinlock */
|
/*
|
||||||
void initlock(struct Spinlock *lk, char *name) {
|
* These are from the original xv6 implementation, with only slight modifications on their return type.
|
||||||
lk->name = name;
|
*
|
||||||
lk->locked = 0;
|
* push_off/pop_off are like intr_off()/intr_on() except that they are matched:
|
||||||
lk->cpu = 0;
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t push_off(void) {
|
||||||
|
int old = intr_get();
|
||||||
|
Cpu *cpu = mycpu();
|
||||||
|
|
||||||
|
intr_off();
|
||||||
|
|
||||||
|
if (cpu->noff == 0)
|
||||||
|
cpu->intena = old;
|
||||||
|
|
||||||
|
cpu->noff += 1;
|
||||||
|
return cpu->noff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
uint32_t pop_off(void) {
|
||||||
* Acquire the lock.
|
Cpu *cpu = mycpu();
|
||||||
* 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.
|
|
||||||
|
|
||||||
if (holding(lk)) // If the lock is already held, panic.
|
if (intr_get())
|
||||||
panic("acquire");
|
PANIC("pop_off - interruptible");
|
||||||
|
|
||||||
// Spin until aquired. See file header for details
|
if (cpu->noff < 1)
|
||||||
while (__sync_lock_test_and_set(&lk->locked, 1) != 0);
|
PANIC("pop_off when cpu->noff < 1");
|
||||||
|
|
||||||
__sync_synchronize(); // No loads/stores after this point
|
cpu->noff -= 1;
|
||||||
|
|
||||||
// Record info about lock acquisition for holding() and debugging.
|
if (cpu->noff == 0 && cpu->intena)
|
||||||
lk->cpu = mycpu();
|
intr_on();
|
||||||
|
|
||||||
|
return cpu->noff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void spinlock_init(spinlock_t *l) {
|
||||||
* Release the lock.
|
l->v = 0;
|
||||||
* Panics if the lock is not held.
|
l->cpu = NULL;
|
||||||
*/
|
}
|
||||||
void release(struct Spinlock *lk) {
|
|
||||||
if (!holding(lk)) // If the lock is not held, panic.
|
|
||||||
panic("release");
|
|
||||||
|
|
||||||
lk->cpu = 0; // 0 means unheld
|
__attribute__((warn_unused_result)) bool spin_trylock(spinlock_t *l) {
|
||||||
__sync_synchronize(); // No loads/stores after this point
|
uint32_t old;
|
||||||
__sync_lock_release(&lk->locked); // Essentially lk->locked = 0
|
// 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();
|
pop_off();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether this cpu is holding the lock.
|
/**
|
||||||
// Interrupts must be off.
|
* Test-and-test-and-set acquire with polite spinning + exponential backoff.
|
||||||
int holding(struct Spinlock *lk) {
|
*/
|
||||||
|
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) {
|
||||||
int r;
|
int r;
|
||||||
r = (lk->locked && lk->cpu == mycpu());
|
r = (l->v && l->cpu == mycpu());
|
||||||
return r;
|
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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,51 +1,22 @@
|
||||||
#ifndef KERNEL_Spinlock_H
|
#ifndef KERNEL_SPINLOCK_H
|
||||||
#define KERNEL_Spinlock_H
|
#define KERNEL_SPINLOCK_H
|
||||||
|
|
||||||
|
#include <proc.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/** Mutual exclusion spin lock */
|
typedef struct {
|
||||||
struct Spinlock {
|
volatile uint32_t v; // 0 = unlocked, 1 = locked
|
||||||
u32 locked; // Is the lock held?
|
Cpu *cpu;
|
||||||
|
} spinlock_t;
|
||||||
|
|
||||||
// NOTE: Perhaps feature gate this?
|
uint32_t push_off(void);
|
||||||
|
uint32_t pop_off(void);
|
||||||
|
|
||||||
// For debugging:
|
void spinlock_init(spinlock_t *l);
|
||||||
char *name; // Name of lock.
|
bool spin_trylock(spinlock_t *l);
|
||||||
struct Cpu *cpu; // The cpu holding the lock.
|
void spin_unlock(spinlock_t *l);
|
||||||
};
|
bool spin_is_holding(spinlock_t *l);
|
||||||
|
void spin_lock(spinlock_t *l);
|
||||||
|
|
||||||
/**
|
#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
|
|
||||||
|
|
7
kern/libkern/stdalign.h
Normal file
7
kern/libkern/stdalign.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef STDALIGN_H
|
||||||
|
#define STDALIGN_H
|
||||||
|
|
||||||
|
#define ALIGN_UP(n, align) (((n) + (align) - 1) & ~((align) - 1))
|
||||||
|
#define ALIGN_DOWN(n, align) ((n) & ~((align) - 1))
|
||||||
|
|
||||||
|
#endif // STDALIGN_H
|
|
@ -8,4 +8,4 @@ typedef __builtin_va_list va_list;
|
||||||
#define va_end(ap) __builtin_va_end(ap)
|
#define va_end(ap) __builtin_va_end(ap)
|
||||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||||
|
|
||||||
#endif
|
#endif // _STDARG_H
|
||||||
|
|
8
kern/libkern/stdbool.h
Normal file
8
kern/libkern/stdbool.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef _STDBOOL_H
|
||||||
|
#define _STDBOOL_H
|
||||||
|
|
||||||
|
/*TODO*/
|
||||||
|
typedef char bool;
|
||||||
|
enum { false = 0, true = 1 };
|
||||||
|
|
||||||
|
#endif // _STDBOOL_H
|
24
kern/libkern/stddef.h
Normal file
24
kern/libkern/stddef.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#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
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
long double ld;
|
||||||
|
#elif __riscv_xlen == 32
|
||||||
|
long long ll;
|
||||||
|
#else
|
||||||
|
double d;
|
||||||
|
#endif
|
||||||
|
void *p;
|
||||||
|
} max_align_t;
|
||||||
|
|
||||||
|
#endif // STDDEF_H
|
|
@ -1,16 +1,63 @@
|
||||||
#pragma once
|
#ifndef STDINT_H
|
||||||
|
#define STDINT_H
|
||||||
|
|
||||||
typedef unsigned char u8;
|
typedef unsigned char u8;
|
||||||
typedef unsigned short u16;
|
typedef unsigned short u16;
|
||||||
typedef unsigned int u32;
|
typedef unsigned int u32;
|
||||||
typedef unsigned long u64;
|
typedef unsigned long u64;
|
||||||
|
|
||||||
|
typedef char i8;
|
||||||
|
typedef short i16;
|
||||||
|
typedef int i32;
|
||||||
|
typedef long i64;
|
||||||
|
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
typedef unsigned int uint32_t;
|
typedef unsigned int uint32_t;
|
||||||
typedef unsigned long uint64_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;
|
typedef uint64_t uintptr_t;
|
||||||
|
|
||||||
// typedef u8 bool;
|
typedef int32_t int_fast16_t;
|
||||||
|
typedef int32_t int_fast32_t;
|
||||||
|
typedef uint32_t uint_fast16_t;
|
||||||
|
typedef uint32_t uint_fast32_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))
|
||||||
|
|
||||||
|
#define INT_FAST16_MIN INT32_MIN
|
||||||
|
#define INT_FAST32_MIN INT32_MIN
|
||||||
|
|
||||||
|
#define INT_FAST16_MAX INT32_MAX
|
||||||
|
#define INT_FAST32_MAX INT32_MAX
|
||||||
|
|
||||||
|
#define UINT_FAST16_MAX UINT32_MAX
|
||||||
|
#define UINT_FAST32_MAX UINT32_MAX
|
||||||
|
|
||||||
|
#define INTPTR_MIN INT64_MIN
|
||||||
|
#define INTPTR_MAX INT64_MAX
|
||||||
|
#define UINTPTR_MAX UINT64_MAX
|
||||||
|
#define PTRDIFF_MIN INT64_MIN
|
||||||
|
#define PTRDIFF_MAX INT64_MAX
|
||||||
|
#define SIZE_MAX UINT64_MAX
|
||||||
|
|
||||||
|
#endif // STDINT_H
|
||||||
|
|
33
kern/libkern/stdio.c
Normal file
33
kern/libkern/stdio.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#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;
|
||||||
|
}
|
20
kern/libkern/stdio.h
Normal file
20
kern/libkern/stdio.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#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
|
13
kern/libkern/stdlib.c
Normal file
13
kern/libkern/stdlib.c
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#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;
|
||||||
|
}
|
11
kern/libkern/stdlib.h
Normal file
11
kern/libkern/stdlib.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#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
|
|
@ -114,18 +114,6 @@ void *memset(void *dest, int c, size_t n) {
|
||||||
return dest;
|
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 *itoa(int value, char *str, int base) {
|
||||||
char *p = str;
|
char *p = str;
|
||||||
char *p1, *p2;
|
char *p1, *p2;
|
||||||
|
@ -166,39 +154,6 @@ char *itoa(int value, char *str, int base) {
|
||||||
return str;
|
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) {
|
int memcmp(const void *s1, const void *s2, size_t len) {
|
||||||
const u8 *a = (const u8 *)s1;
|
const u8 *a = (const u8 *)s1;
|
||||||
const u8 *b = (const u8 *)s2;
|
const u8 *b = (const u8 *)s2;
|
||||||
|
@ -223,3 +178,20 @@ size_t strnlen(const char *s, size_t maxlen) {
|
||||||
}
|
}
|
||||||
return len;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define KERNEL_STRING_H
|
#define KERNEL_STRING_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
// void *memcpy(void *s1, const void *s2, size_t n);
|
// void *memcpy(void *s1, const void *s2, size_t n);
|
||||||
// void *memmove(void *s1, const void *s2, size_t n);
|
// void *memmove(void *s1, const void *s2, size_t n);
|
||||||
|
@ -30,16 +31,17 @@ size_t strlen(const char *s);
|
||||||
/** Return length of string `s`, up to a max of `maxlen` bytes */
|
/** Return length of string `s`, up to a max of `maxlen` bytes */
|
||||||
size_t strnlen(const char *s, size_t maxlen);
|
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:
|
// TODO: These:
|
||||||
/*
|
/*
|
||||||
int strcmp(const char *s1, const char *s2);
|
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 *strcpy(char *dst, const char *src);
|
||||||
char *strncpy(char *dst, const char *src, size_t n);
|
|
||||||
|
|
||||||
char *strchr(const char *s, int c);
|
char *strchr(const char *s, int c);
|
||||||
char *strrchr(const char *s, int c);
|
char *strrchr(const char *s, int c);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#endif
|
#endif // KERNEL_STRING_H
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
/* QEMU memory maps a UART device here. */
|
/* QEMU memory maps a UART device here. */
|
||||||
#define UART_BASE ((volatile char *)0x10000000)
|
#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++);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,4 @@
|
||||||
/** Send a single character to the UART device */
|
/** Send a single character to the UART device */
|
||||||
void uart_putc(char c);
|
void uart_putc(char c);
|
||||||
|
|
||||||
/** Send a **NULL TERMINATED** string to the UART device */
|
#endif // UART_KERNEL_H
|
||||||
void uart_puts(const char *s);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
28
kern/libkern/util.h
Normal file
28
kern/libkern/util.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#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
|
22
kern/proc.h
22
kern/proc.h
|
@ -1,5 +1,7 @@
|
||||||
|
#ifndef PROC_H
|
||||||
|
#define PROC_H
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <spinlock.h>
|
|
||||||
#include <riscv.h>
|
#include <riscv.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -13,7 +15,7 @@ typedef enum {
|
||||||
} ProcessState;
|
} ProcessState;
|
||||||
|
|
||||||
/** Saved registers for kernel context switches. */
|
/** Saved registers for kernel context switches. */
|
||||||
struct Context {
|
typedef struct Context {
|
||||||
uint64_t ra;
|
uint64_t ra;
|
||||||
uint64_t sp;
|
uint64_t sp;
|
||||||
|
|
||||||
|
@ -30,18 +32,18 @@ struct Context {
|
||||||
uint64_t s9;
|
uint64_t s9;
|
||||||
uint64_t s10;
|
uint64_t s10;
|
||||||
uint64_t s11;
|
uint64_t s11;
|
||||||
};
|
} Context;
|
||||||
|
|
||||||
/** Per-CPU state. */
|
/** Per-CPU state. */
|
||||||
struct Cpu {
|
typedef struct cpu_t {
|
||||||
struct Process *proc; // The process running on this cpu, or null.
|
struct Process *proc; // The process running on this cpu, or null.
|
||||||
struct Context context; // swtch() here to enter scheduler().
|
struct Context context; // swtch() here to enter scheduler().
|
||||||
int noff; // Depth of push_off() nesting.
|
int noff; // Depth of push_off() nesting.
|
||||||
int intena; // Were interrupts enabled before push_off()?
|
int intena; // Were interrupts enabled before push_off()?
|
||||||
};
|
} Cpu;
|
||||||
|
|
||||||
/** Saved registers for kernel context switches. */
|
/** Saved registers for kernel context switches. */
|
||||||
typedef struct {
|
typedef struct TrapFrame_t {
|
||||||
/* 0 */ uint64_t kernel_satp; // kernel page table
|
/* 0 */ uint64_t kernel_satp; // kernel page table
|
||||||
/* 8 */ uint64_t kernel_sp; // top of process's kernel stack
|
/* 8 */ uint64_t kernel_sp; // top of process's kernel stack
|
||||||
/* 16 */ uint64_t kernel_trap; // usertrap()
|
/* 16 */ uint64_t kernel_trap; // usertrap()
|
||||||
|
@ -78,11 +80,13 @@ typedef struct {
|
||||||
/* 264 */ uint64_t t4;
|
/* 264 */ uint64_t t4;
|
||||||
/* 272 */ uint64_t t5;
|
/* 272 */ uint64_t t5;
|
||||||
/* 280 */ uint64_t t6;
|
/* 280 */ uint64_t t6;
|
||||||
} TrapFrame_t;
|
} TrapFrame;
|
||||||
|
|
||||||
struct Cpu *mycpu(void);
|
Cpu *mycpu(void);
|
||||||
|
|
||||||
extern struct Cpu cpus[NCPU];
|
extern Cpu cpus[NCPU];
|
||||||
|
|
||||||
/** Per-process state */
|
/** Per-process state */
|
||||||
struct Proc {};
|
struct Proc {};
|
||||||
|
|
||||||
|
#endif // PROC_H
|
||||||
|
|
121
kern/slab.h
Normal file
121
kern/slab.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#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
|
|
@ -1,10 +1,15 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <banner.h>
|
||||||
|
#include <buddy.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <ispinlock.h>
|
|
||||||
#include <kalloc.h>
|
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
#include <panic.h>
|
||||||
#include <proc.h>
|
#include <proc.h>
|
||||||
#include <riscv.h>
|
#include <riscv.h>
|
||||||
|
#include <spinlock.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <uart.h>
|
#include <uart.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,31 +41,26 @@ void start() {
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
/* Here we will do a bunch of initialization steps */
|
/* Here we will do a bunch of initialization steps */
|
||||||
kalloc_init();
|
memory_sweep(heap_start, heap_end);
|
||||||
uart_puts("Hello Neptune!\n");
|
buddy_init(heap_start, heap_end);
|
||||||
spinlock_init(&sl);
|
spinlock_init(&sl);
|
||||||
|
for (int i = 0; i < banner_len; i++) uart_putc(banner[i]);
|
||||||
|
__sync_synchronize();
|
||||||
hold = 0;
|
hold = 0;
|
||||||
} else {
|
} else {
|
||||||
while (hold);
|
while (hold);
|
||||||
}
|
}
|
||||||
|
|
||||||
// spin_lock(&sl);
|
|
||||||
//
|
|
||||||
// uart_puts("Hart number: ");
|
|
||||||
// uart_putc(id + '0');
|
|
||||||
// uart_putc('\n');
|
|
||||||
//
|
|
||||||
// spin_unlock(&sl);
|
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
spin_lock(&sl);
|
spin_lock(&sl);
|
||||||
uart_puts("Core count: ");
|
kprintf("Core count: %d\n", max_hart);
|
||||||
uart_putc(max_hart + '0');
|
|
||||||
uart_putc('\n');
|
if (max_hart == NCPU)
|
||||||
if (max_hart == NCPU) {
|
kprintf("All cores up!\n");
|
||||||
uart_puts("All cores up!");
|
else
|
||||||
uart_putc('\n');
|
PANIC("Some cores seem to have been enumerated incorrectly!\n");
|
||||||
}
|
|
||||||
|
kprintf("To exit qemu, press CTRL+a followed by x\n");
|
||||||
spin_unlock(&sl);
|
spin_unlock(&sl);
|
||||||
}
|
}
|
||||||
|
|
26
licenses/LICENSE.mini-printf
Normal file
26
licenses/LICENSE.mini-printf
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
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.
|
173
licenses/LICENSE.monocypher
Normal file
173
licenses/LICENSE.monocypher
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
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.
|
193
licenses/LICENSE.musl
Normal file
193
licenses/LICENSE.musl
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
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.
|
23
licenses/LICENSE.xv6-riscv
Normal file
23
licenses/LICENSE.xv6-riscv
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
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.
|
Loading…
Add table
Reference in a new issue