Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3f74e55322 | ||
![]() |
13b91e7aae | ||
![]() |
2830ad60e1 | ||
![]() |
ae356930d8 | ||
![]() |
ea016307cf | ||
![]() |
d078e7fb93 |
50 changed files with 856 additions and 1797 deletions
|
@ -1,4 +0,0 @@
|
|||
**/mini-printf.c
|
||||
**/mini-printf.h
|
||||
**/monocypher.c
|
||||
**/monocypher.h
|
153
Makefile
153
Makefile
|
@ -1,19 +1,6 @@
|
|||
# See: https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases
|
||||
# See: https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases
|
||||
GCC_VER := 14.2.0-3
|
||||
QEMU_VER := 8.2.6-1
|
||||
|
||||
SYS_TOOLPREFIX ?= riscv64-linux-gnu
|
||||
|
||||
GCC_PATH := toolchain/gcc/bin
|
||||
LOCAL_TOOLPREFIX := $(GCC_PATH)/riscv-none-elf
|
||||
|
||||
# TODO: Some wildcard condition to detect prefix
|
||||
TOOLPREFIX := $(LOCAL_TOOLPREFIX)
|
||||
# TOOLPREFIX := $(SYS_TOOLPREFIX)
|
||||
|
||||
QEMU_PATH := toolchain/qemu/bin
|
||||
QEMU = $(QEMU_PATH)/qemu-system-riscv64
|
||||
# TOOLPREFIX = riscv64-linux-gnu
|
||||
# TOOLPREFIX = toolchain/xpack-riscv-none-elf-gcc-14.2.0-3/bin/riscv-none-elf
|
||||
TOOLPREFIX = toolchain/gcc/bin/riscv-none-elf
|
||||
|
||||
CC = $(TOOLPREFIX)-gcc
|
||||
AS = $(TOOLPREFIX)-as
|
||||
|
@ -23,18 +10,14 @@ OBJDUMP = $(TOOLPREFIX)-objdump
|
|||
|
||||
ASFLAGS = -march=rv64gc -mabi=lp64
|
||||
|
||||
LDFLAGS = -Tkern/kernel.ld
|
||||
LDFLAGS = -Tkernel.ld
|
||||
LDFLAGS += -m elf64lriscv
|
||||
|
||||
CFLAGS = -Wall -Werror -O
|
||||
CFLAGS += -Wno-unused-result
|
||||
CFLAGS += -mcmodel=medany
|
||||
CFLAGS += -march=rv64gc -mabi=lp64
|
||||
CFLAGS += -ffreestanding
|
||||
CFLAGS += -fno-common
|
||||
CFLAGS += -nostdlib
|
||||
CFLAGS += -mno-relax
|
||||
CFLAGS += -std=gnu99
|
||||
CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
|
||||
|
||||
CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support
|
||||
CFLAGS += -MD # Generate header dependency files (.d)
|
||||
|
@ -42,113 +25,93 @@ CFLAGS += -fno-pie -no-pie # Fixed address linking
|
|||
CFLAGS += -ggdb -gdwarf-2 # GDB debug info
|
||||
CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB
|
||||
|
||||
KCFLAGS += $(CGFLAGS)
|
||||
KCFLAGS += -DNEPTUNE_KERNEL
|
||||
KCFLAGS += -Ikern
|
||||
KCFLAGS += -Ikern/libkern
|
||||
KCFLAGS += -I.
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I./kern
|
||||
CFLAGS += -I./kern/libkern
|
||||
CFLAGS += -Ilib
|
||||
|
||||
all: kern/kernel.elf
|
||||
build: all
|
||||
all: kernel.elf
|
||||
|
||||
quickstart:
|
||||
make get_toolchain && bear -- make -j$(nproc) && make qemu
|
||||
main: main.o
|
||||
|
||||
KERNEL_OBJ := \
|
||||
kern/entry.o \
|
||||
kern/start.o \
|
||||
kern/libkern/freelist.o \
|
||||
kern/libkern/string.o \
|
||||
kern/libkern/proc.o \
|
||||
kern/libkern/uart.o \
|
||||
kern/libkern/panic.o \
|
||||
kern/libkern/memory.o \
|
||||
kern/libkern/spinlock.o \
|
||||
kern/libkern/mini-printf.o \
|
||||
kern/libkern/stdio.o \
|
||||
kern/libkern/buddy.o \
|
||||
kern/libkern/badrand.o
|
||||
|
||||
kern/kernel.elf: $(KERNEL_OBJ)
|
||||
kernel.elf: entry.o start.o kern/libkern/string.o kern/libkern/proc.o kern/libkern/uart.o kern/libkern/panic.o kern/kalloc.o kern/libkern/memory.o kern/ispinlock.o kern/libkern/spinlock.o kern/libkern/string.o kern/libkern/mini-printf.o
|
||||
@echo LD $@
|
||||
@$(LD) $(LDFLAGS) -o $@ $^
|
||||
|
||||
%.o: %.c
|
||||
@echo CC $@
|
||||
@$(CC) $(CFLAGS) -nostdinc -I. -c $< -o $@
|
||||
@$(CC) $(KCFLAGS) -nostdinc -I. -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
@echo AS $@
|
||||
@$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
qemu: kern/kernel.elf
|
||||
qemu: kernel.elf
|
||||
@echo QEMU $<
|
||||
@$(QEMU) -machine virt -bios none -nographic -m 128M -smp 4 -kernel $<
|
||||
@qemu-system-riscv64 -machine virt -bios none -nographic -m 128M -smp 4 -kernel kernel.elf
|
||||
|
||||
clean:
|
||||
find . -type f -name '*.[od(elf)]' -exec rm -f {} +
|
||||
rm -f *.o *.elf *.d lib/*.o lib/*.d
|
||||
fd -e o -x rm # TODO: Should only depend on posix
|
||||
|
||||
format:
|
||||
find kern -type f -name '*.[ch]' -exec clang-format -i {} \;
|
||||
-include *.d
|
||||
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
@echo " quickstart – Runs get_toolchain, build and qemu in sequence. Generates compile-commands.json. RUN ONLY ONCE"
|
||||
@echo " build - Build the project"
|
||||
@echo " qemu - Run the kernel in qemu"
|
||||
@echo " clean – Remove build artifacts (*.o, *.d, *.elf)"
|
||||
@echo " distclean – Same as clean, but also purges toolchain"
|
||||
@echo " format – Run clang-format over all kernel sources"
|
||||
@echo " get_toolchain – Fetchest the toolchain and extracts it into ./toolchain"
|
||||
@echo " info – Get some general info on toolchain versions and flags"
|
||||
# --------------------------------------------------------------------
|
||||
# Toolchain configuration
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
TOOLCHAIN_DIR := toolchain
|
||||
|
||||
QEMU_TARBALL := xpack-qemu-riscv-$(QEMU_VER)-linux-x64.tar.gz
|
||||
GCC_TARBALL := xpack-riscv-none-elf-gcc-$(GCC_VER)-linux-x64.tar.gz
|
||||
# Versions
|
||||
QEMU_VER := 8.2.6-1
|
||||
GCC_VER := 14.2.0-3
|
||||
|
||||
# Filenames
|
||||
QEMU_TARBALL := xpack-qemu-riscv-$(QEMU_VER)-linux-arm.tar.gz
|
||||
GCC_TARBALL := xpack-riscv-none-elf-gcc-$(GCC_VER)-linux-arm.tar.gz
|
||||
|
||||
# URLs
|
||||
QEMU_URL := https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases/download/v$(QEMU_VER)/$(QEMU_TARBALL)
|
||||
GCC_URL := https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v$(GCC_VER)/$(GCC_TARBALL)
|
||||
|
||||
QEMU_TARPATH := toolchain/$(QEMU_TARBALL)
|
||||
GCC_TARPATH := toolchain/$(GCC_TARBALL)
|
||||
# Paths
|
||||
QEMU_TARPATH := toolchain/xpack-qemu-riscv-8.2.6-1-linux-arm.tar.gz
|
||||
GCC_TARPATH := toolchain/xpack-riscv-none-elf-gcc-14.2.0-3-linux-arm.tar.gz
|
||||
|
||||
# Extracted directories
|
||||
QEMU_DIR := $(TOOLCHAIN_DIR)/xpack-qemu-riscv-$(QEMU_VER)
|
||||
GCC_DIR := $(TOOLCHAIN_DIR)/xpack-riscv-none-elf-gcc-$(GCC_VER)
|
||||
|
||||
# Symlink targets
|
||||
QEMU_SYM_DIR := xpack-qemu-riscv-$(QEMU_VER)
|
||||
GCC_SYM_DIR := xpack-riscv-none-elf-gcc-$(GCC_VER)
|
||||
|
||||
$(TOOLCHAIN_DIR):
|
||||
@mkdir -p $@
|
||||
# Final symlink/alias
|
||||
GCC_ALIAS := gcc
|
||||
QEMU_ALIAS := qemu
|
||||
|
||||
$(QEMU_TARPATH): $(TOOLCHAIN_DIR)
|
||||
@echo "Fetching qemu-riscv-xpack: v$(QEMU_VER)"
|
||||
@curl -# -L -o $@ $(QEMU_URL)
|
||||
QEMU_TARPATH:
|
||||
curl -# -L -o $@ $(QEMU_URL)
|
||||
|
||||
$(GCC_TARPATH): $(TOOLCHAIN_DIR)
|
||||
@echo "Fetching riscv-none-elf-gcc-xpack: v$(GCC_VER)"
|
||||
@curl -# -L -o $@ $(GCC_URL)
|
||||
GCC_TARPATH:
|
||||
curl -# -L -o $@ $(GCC_URL)
|
||||
|
||||
get_toolchain: $(TOOLCHAIN_DIR) $(GCC_TARPATH) $(QEMU_TARPATH)
|
||||
@echo "Unpacking qemu..."
|
||||
@cd toolchain && tar xf $(QEMU_TARBALL)
|
||||
@echo "Unpacking gcc..."
|
||||
@cd toolchain && tar xf $(GCC_TARBALL)
|
||||
@cd $(TOOLCHAIN_DIR) && ln -sfn $(QEMU_SYM_DIR) qemu
|
||||
@cd $(TOOLCHAIN_DIR) && ln -sfn $(GCC_SYM_DIR) gcc
|
||||
@echo "Toolchain in place, ready to make!"
|
||||
extractions:
|
||||
cd toolchain && tar xf $(QEMU_TARBALL)
|
||||
cd toolchain && tar xf $(GCC_TARBALL)
|
||||
|
||||
toolchain: $(QEMU_TARPATH) $(GCC_TARPATH)
|
||||
mkdir -p toolchain
|
||||
cd toolchain && tar xf $(QEMU_TARBALL)
|
||||
cd toolchain && tar xf $(GCC_TARBALL)
|
||||
cd $(TOOLCHAIN_DIR) && ln -sfn $(QEMU_SYM_DIR) $(QEMU_ALIAS)
|
||||
cd $(TOOLCHAIN_DIR) && ln -sfn $(GCC_SYM_DIR) $(GCC_ALIAS)
|
||||
|
||||
distclean: clean
|
||||
rm -rf $(TOOLCHAIN_DIR)
|
||||
|
||||
info:
|
||||
@echo "Using qemu v$(QEMU_VER): $(QEMU)"
|
||||
@echo "Using toolchain gcc v$(GCC_VER): $(TOOLPREFIX)"
|
||||
@echo "CFLAGS:"
|
||||
@for flag in $(CFLAGS); do \
|
||||
printf " %s\n" "$$flag"; \
|
||||
done
|
||||
@echo "LDFLAGS:"
|
||||
@for flag in $(LDFLAGS); do \
|
||||
printf " %s\n" "$$flag"; \
|
||||
done
|
||||
|
||||
-include *.d
|
||||
|
||||
.PHONY: all qemu info quickstart help build
|
||||
.PHONY: all toolchain
|
||||
|
|
69
README.md
69
README.md
|
@ -5,56 +5,7 @@ Inspired by xv6
|
|||
For a quick reference on RISC-V assembly:
|
||||
- https://risc-v.guru/instructions/
|
||||
|
||||
Some low-level string format routines borrowed from [mini-printf](https://github.com/mludvig/mini-printf)
|
||||
|
||||
### Directory outline
|
||||
|
||||
The planned directory outline is as follows:
|
||||
```
|
||||
root
|
||||
├── kern # General kernel sources
|
||||
│ ├── libkern # Kernel specific library routines
|
||||
│ ├── memory # Memory related code (kalloc, buddy and friends)
|
||||
│ └── arch # Architecture specific functionality
|
||||
├── libc # Userspace C library
|
||||
└── user # Userspace programs
|
||||
```
|
||||
|
||||
### Quick Start
|
||||
|
||||
On a linux machine, make sure that you have `make` and `curl` in path. The rest
|
||||
of the tooling (gcc, qemu) will be handled by the build system. For extra convenience,
|
||||
you could also use `bear` for generating "compile_commands.json". This is useful for helping
|
||||
clangd pick up the correct paths, and will result in better in-editor diagnostics and warnings.
|
||||
For development, `clang-format` and `find` will also be useful.
|
||||
|
||||
In short, for debian/redhat:
|
||||
```sh
|
||||
sudo apt install bear make curl clang-format find
|
||||
sudo dnf install bear make curl clang-format find
|
||||
```
|
||||
Im sure its the same on alpine/arch and friends. You're a linux user, put on those big boy pants
|
||||
and figure it out. For more info you can check `make help`.
|
||||
|
||||
```sh
|
||||
make get_toolchain # Dont worry, is will land locally inside project directory
|
||||
make -j$(nproc)
|
||||
make qemu
|
||||
```
|
||||
|
||||
To generate "compile_commands.json":
|
||||
```sh
|
||||
make clean # To get a full build
|
||||
bear -- make -j$(nproc)
|
||||
```
|
||||
|
||||
The project can be cleaned with:
|
||||
```sh
|
||||
make clean # Wipes .o, .d, .elf
|
||||
make distclean # Wipes the above, but also removes toolchain
|
||||
```
|
||||
|
||||
### Toolchains:
|
||||
Toolchains:
|
||||
- https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
|
||||
- https://github.com/xpack-dev-tools/qemu-riscv-xpack/
|
||||
|
||||
|
@ -64,8 +15,6 @@ make distclean # Wipes the above, but also removes toolchain
|
|||
> term trap, largely because it was the term used by the PDP11/40 and therefore is the
|
||||
> conventional Unix term.
|
||||
|
||||
### Notes/Misc
|
||||
|
||||
| Register | Name | Privilege Level | Description |
|
||||
|-------------|----------------------------|------------------|-----------------------------------------------------------------------------|
|
||||
| `mstatus` | Machine Status Register | Machine | Holds global interrupt enable, previous privilege mode, etc. |
|
||||
|
@ -84,18 +33,12 @@ make distclean # Wipes the above, but also removes toolchain
|
|||
| `mip` | Machine Interrupt Pending | Machine | Indicates pending interrupts. |
|
||||
| `mie` | Machine Interrupt Enable | Machine | Controls which interrupts are enabled. |
|
||||
|
||||
### TODO
|
||||
- [x] Kassert, some macro in the form of `ASSERT(condition, "This went wrong")`
|
||||
- [ ] [FatFs](https://elm-chan.org/fsw/ff/)
|
||||
- [ ] Integrate [Kconfig](https://github.com/ulfalizer/Kconfiglib)
|
||||
- [ ] Klog, or some form of logging that is directable and more than just kprintf
|
||||
# Notes
|
||||
|
||||
### Libc Implementations
|
||||
## Libc Implementations
|
||||
|
||||
- [Libc reference](https://discapes.github.io/libc-reference/)
|
||||
|
||||
- [uClibc](https://uclibc.org/)
|
||||
- [musl libc](https://musl.libc.org/)
|
||||
- [dietlibc](http://www.fefe.de/dietlibc/)
|
||||
[uClibc](https://uclibc.org/)
|
||||
[musl libc](https://musl.libc.org/)
|
||||
[dietlibc](http://www.fefe.de/dietlibc/)
|
||||
|
||||
[Comparison of C/POSIX standard library implementations for Linux](https://www.etalabs.net/compare_libcs.html) (by musl author)
|
||||
|
|
3
config.h
3
config.h
|
@ -1,5 +1,3 @@
|
|||
#ifndef KERNEL_CONFIG_H
|
||||
#define KERNEL_CONFIG_H
|
||||
/*
|
||||
* Number of CPU's For now, this is hard-coded here. It will likely be
|
||||
* dynamically discovered in the future.
|
||||
|
@ -8,4 +6,3 @@
|
|||
|
||||
/* Maximum number of files open */
|
||||
#define NOFILE 10
|
||||
#endif // KERNEL_CONFIG_H
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef BANNER_H
|
||||
#define BANNER_H
|
||||
|
||||
unsigned char banner[] = {
|
||||
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x34, 0x6d, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20,
|
||||
0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x37, 0x38, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x5f, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x34, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x38, 0x6d, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
|
||||
0x32, 0x31, 0x34, 0x6d, 0x7c, 0x20, 0x5c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x5f, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
|
||||
0x3b, 0x32, 0x30, 0x38, 0x6d, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38,
|
||||
0x3b, 0x35, 0x3b, 0x32, 0x30, 0x39, 0x6d, 0x7c, 0x5f, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x1b, 0x5b,
|
||||
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x33, 0x6d, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20,
|
||||
0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x39, 0x6d, 0x7c, 0x20, 0x20,
|
||||
0x5c, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x33, 0x6d, 0x5f, 0x20,
|
||||
0x5c, 0x20, 0x27, 0x5f, 0x20, 0x5c, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x34, 0x6d,
|
||||
0x5f, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39,
|
||||
0x38, 0x6d, 0x27, 0x5f, 0x20, 0x5c, 0x20, 0x2f, 0x20, 0x5f, 0x20, 0x5c, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b,
|
||||
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x34, 0x6d, 0x7c, 0x20, 0x7c, 0x5c, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x1b,
|
||||
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x38, 0x6d, 0x5f, 0x5f, 0x2f, 0x20, 0x7c, 0x5f, 0x29, 0x20, 0x7c,
|
||||
0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x39, 0x6d, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c,
|
||||
0x20, 0x7c, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x36, 0x33, 0x6d, 0x7c, 0x20, 0x7c, 0x20, 0x7c,
|
||||
0x20, 0x20, 0x5f, 0x5f, 0x2f, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39,
|
||||
0x39, 0x6d, 0x7c, 0x5f, 0x7c, 0x20, 0x5c, 0x5f, 0x7c, 0x5c, 0x5f, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
|
||||
0x36, 0x33, 0x6d, 0x5f, 0x5f, 0x7c, 0x20, 0x2e, 0x5f, 0x5f, 0x2f, 0x20, 0x5c, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
|
||||
0x3b, 0x31, 0x36, 0x34, 0x6d, 0x5f, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x1b, 0x5b, 0x33, 0x38,
|
||||
0x3b, 0x35, 0x3b, 0x31, 0x32, 0x38, 0x6d, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x5f, 0x7c, 0x1b, 0x5b,
|
||||
0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x36, 0x34, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x32, 0x38, 0x6d, 0x20, 0x20, 0x7c, 0x5f,
|
||||
0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x32, 0x39, 0x6d, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x33, 0x6d, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x0a, 0x1b, 0x5b, 0x30, 0x6d};
|
||||
|
||||
unsigned int banner_len = 531;
|
||||
|
||||
#endif // BANNER_H
|
45
kern/ispinlock.c
Normal file
45
kern/ispinlock.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "ispinlock.h"
|
||||
|
||||
void spinlock_init(spinlock_t *l) {
|
||||
l->v = 0;
|
||||
}
|
||||
|
||||
__attribute__((warn_unused_result)) bool spin_trylock(spinlock_t *l) {
|
||||
uint32_t old;
|
||||
// old = xchg_acquire(&l->v, 1) using AMO
|
||||
__asm__ volatile("amoswap.w.aq %0, %2, (%1)\n" : "=&r"(old) : "r"(&l->v), "r"(1u) : "memory");
|
||||
return old == 0;
|
||||
}
|
||||
|
||||
void spin_unlock(spinlock_t *l) {
|
||||
// Release: store 0 with .rl ordering.
|
||||
uint32_t dummy;
|
||||
__asm__ volatile("amoswap.w.rl %0, %2, (%1)\n" : "=&r"(dummy) : "r"(&l->v), "r"(0u) : "memory");
|
||||
}
|
||||
|
||||
// Optional: tiny pause/backoff (works even if Zihintpause isn't present).
|
||||
// See: https://github.com/riscv/riscv-isa-manual/blob/main/src/zihintpause.adoc
|
||||
static inline void cpu_relax(void) {
|
||||
#if defined(__riscv_zihintpause)
|
||||
__asm__ volatile("pause");
|
||||
#else
|
||||
__asm__ volatile("nop");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test-and-test-and-set acquire with polite spinning + exponential backoff.
|
||||
void spin_lock(spinlock_t *l) {
|
||||
unsigned backoff = 1;
|
||||
for (;;) {
|
||||
if (spin_trylock(l))
|
||||
return;
|
||||
|
||||
// Contended: spin on plain loads (no AMO) until it looks free.
|
||||
while (__atomic_load_n(&l->v, __ATOMIC_RELAXED) != 0) {
|
||||
for (unsigned i = 0; i < backoff; ++i) cpu_relax();
|
||||
if (backoff < 1u << 12)
|
||||
backoff <<= 1;
|
||||
}
|
||||
// Try again; loop.
|
||||
}
|
||||
}
|
11
kern/ispinlock.h
Normal file
11
kern/ispinlock.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t v; // 0 = unlocked, 1 = locked
|
||||
} spinlock_t;
|
||||
|
||||
void spinlock_init(spinlock_t *l);
|
||||
bool spin_trylock(spinlock_t *l);
|
||||
void spin_unlock(spinlock_t *l);
|
||||
void spin_lock(spinlock_t *l);
|
76
kern/kalloc.c
Normal file
76
kern/kalloc.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include <ispinlock.h>
|
||||
#include <kalloc.h>
|
||||
#include <memory.h>
|
||||
#include <panic.h>
|
||||
#include <riscv.h>
|
||||
#include <string.h>
|
||||
#include <types.h>
|
||||
|
||||
// Physical memory allocator, for user processes,
|
||||
// kernel stacks, page-table pages,
|
||||
// and pipe buffers. Allocates whole 4096-byte pages.
|
||||
|
||||
/** Free list of physical pages. */
|
||||
void freerange(void *physaddr_start, void *physaddr_end);
|
||||
|
||||
/** First address after kernel. Provided kernel.ld */
|
||||
extern char kernel_end[];
|
||||
|
||||
/** A run is a node in the free list. */
|
||||
struct Run {
|
||||
struct Run *next;
|
||||
};
|
||||
|
||||
/** Kernel memory allocator. */
|
||||
struct {
|
||||
spinlock_t lock;
|
||||
struct Run *freelist;
|
||||
} kmem;
|
||||
|
||||
void kalloc_init() {
|
||||
spinlock_init(&kmem.lock);
|
||||
freerange(kernel_end, (void *)PHYSTOP);
|
||||
}
|
||||
|
||||
void freerange(void *physaddr_start, void *physaddr_end) {
|
||||
char *p;
|
||||
p = (char *)PGROUNDUP((u64)physaddr_start);
|
||||
for (; p + PGSIZE <= (char *)physaddr_end; p += PGSIZE) kfree(p);
|
||||
}
|
||||
|
||||
void kfree(void *pa) {
|
||||
struct Run *r;
|
||||
|
||||
// Assert that page is a ligned to a page boundary and that its correctly
|
||||
// sized
|
||||
if (((u64)pa % PGSIZE) != 0 || (char *)pa < kernel_end || (u64)pa >= PHYSTOP)
|
||||
panic("kfree");
|
||||
|
||||
// Fill with junk to catch dangling refs.
|
||||
memset(pa, 1, PGSIZE);
|
||||
|
||||
r = (struct Run *)pa;
|
||||
|
||||
spin_lock(&kmem.lock);
|
||||
r->next = kmem.freelist;
|
||||
kmem.freelist = r;
|
||||
spin_unlock(&kmem.lock);
|
||||
}
|
||||
|
||||
void *kalloc(void) {
|
||||
struct Run *r;
|
||||
|
||||
spin_lock(&kmem.lock);
|
||||
|
||||
r = kmem.freelist;
|
||||
|
||||
if (r)
|
||||
kmem.freelist = r->next;
|
||||
|
||||
spin_unlock(&kmem.lock);
|
||||
|
||||
if (r)
|
||||
memset((char *)r, 5, PGSIZE); // fill with junk
|
||||
|
||||
return (void *)r;
|
||||
}
|
33
kern/kalloc.h
Normal file
33
kern/kalloc.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef KALLOC_KERNEL_H
|
||||
#define KALLOC_KERNEL_H
|
||||
|
||||
/**
|
||||
* Kernel memory allocator
|
||||
*
|
||||
* Allocate one 4096-byte page of physical memory.
|
||||
* Returns a pointer that the kernel can use.
|
||||
* Returns 0 if the memory cannot be allocated.
|
||||
* See: kalloc.c
|
||||
*/
|
||||
void *kalloc(void);
|
||||
|
||||
/**
|
||||
* Kernel memory allocator
|
||||
*
|
||||
* Free the page of physical memory pointed at by pa,
|
||||
* which normally should have been returned by a
|
||||
* call to kalloc(). (The exception is when
|
||||
* initializing the allocator; see kinit above.)
|
||||
* See: kalloc.c
|
||||
*/
|
||||
void kfree(void *);
|
||||
|
||||
/**
|
||||
* Initialize kernel memory allocator
|
||||
*
|
||||
* Called by main() on the way to the kernel's main loop.
|
||||
* See: kalloc.c
|
||||
*/
|
||||
void kalloc_init(void);
|
||||
|
||||
#endif
|
103
kern/kprint.c
Normal file
103
kern/kprint.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static void append_char(char **buf, size_t *remaining, char c) {
|
||||
if (*remaining > 1) { // Leave space for null terminator
|
||||
**buf = c;
|
||||
(*buf)++;
|
||||
(*remaining)--;
|
||||
}
|
||||
}
|
||||
|
||||
static void append_str(char **buf, size_t *remaining, const char *str) {
|
||||
while (*str) {
|
||||
append_char(buf, remaining, *str++);
|
||||
}
|
||||
}
|
||||
|
||||
static void append_int(char **buf, size_t *remaining, int value, int base) {
|
||||
char tmp[32];
|
||||
const char *digits = "0123456789abcdef";
|
||||
bool neg = false;
|
||||
int i = 0;
|
||||
|
||||
if (base == 10 && value < 0) {
|
||||
neg = true;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
do {
|
||||
tmp[i++] = digits[value % base];
|
||||
value /= base;
|
||||
} while (value && i < (int)sizeof(tmp));
|
||||
|
||||
if (neg) {
|
||||
tmp[i++] = '-';
|
||||
}
|
||||
|
||||
while (i--) {
|
||||
append_char(buf, remaining, tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int kvsnprintf(char *buf, size_t size, const char *fmt, va_list args) {
|
||||
char *p = buf;
|
||||
size_t remaining = size;
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt != '%') {
|
||||
append_char(&p, &remaining, *fmt++);
|
||||
continue;
|
||||
}
|
||||
fmt++; // skip '%'
|
||||
|
||||
switch (*fmt) {
|
||||
case 's':
|
||||
append_str(&p, &remaining, va_arg(args, const char *));
|
||||
break;
|
||||
case 'd':
|
||||
append_int(&p, &remaining, va_arg(args, int), 10);
|
||||
break;
|
||||
case 'x':
|
||||
append_int(&p, &remaining, va_arg(args, unsigned int), 16);
|
||||
break;
|
||||
case 'c':
|
||||
append_char(&p, &remaining, (char)va_arg(args, int));
|
||||
break;
|
||||
case '%':
|
||||
append_char(&p, &remaining, '%');
|
||||
break;
|
||||
default:
|
||||
append_char(&p, &remaining, '?');
|
||||
break;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
|
||||
if (remaining > 0) {
|
||||
*p = '\0';
|
||||
} else {
|
||||
buf[size - 1] = '\0';
|
||||
}
|
||||
|
||||
return (int)(p - buf);
|
||||
}
|
||||
|
||||
int ksnprintf(char *buf, size_t size, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int ret = kvsnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kprintf(const char *fmt, ...) {
|
||||
char buffer[256];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
kvsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// Now send buffer to your console/serial output
|
||||
console_write(buffer);
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include <panic.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define assert(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
PANIC("Assertion failed: %s\n", #cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define assert_msg(cond, fmt, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
PANIC("Assertion failed: %s: " fmt, #cond, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
|
@ -1,35 +0,0 @@
|
|||
#include "badrand.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define PRAND_BUILD_SEED \
|
||||
((uint64_t)(__TIME__[0]) * (uint64_t)(__TIME__[1]) * (uint64_t)(__TIME__[3]) * (uint64_t)(__TIME__[4]) * \
|
||||
(uint64_t)(__TIME__[6]) * (uint64_t)(__TIME__[7]))
|
||||
|
||||
static uint64_t seed = PRAND_BUILD_SEED * 6364136223846793005ULL + 1;
|
||||
|
||||
uint64_t badrand() {
|
||||
seed = seed * 6364136223846793005ULL + 1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
uint64_t badrand_range(uint64_t min, uint64_t max) {
|
||||
uint64_t range = max - min + 1;
|
||||
uint64_t x;
|
||||
uint64_t limit = UINT64_MAX - (UINT64_MAX % range);
|
||||
|
||||
do {
|
||||
x = badrand();
|
||||
} while (x > limit);
|
||||
|
||||
return min + (x % range);
|
||||
}
|
||||
|
||||
void sbadprand(uint64_t s) {
|
||||
if (s) {
|
||||
seed ^= (s * 0x9e3779b97f4a7c15ULL) + (seed << 6) + (seed >> 2);
|
||||
} else {
|
||||
seed ^= PRAND_BUILD_SEED;
|
||||
}
|
||||
}
|
||||
|
||||
#undef PRAND_BUILD_SEED
|
|
@ -1,43 +0,0 @@
|
|||
#ifndef BADRAND_H
|
||||
#define BADRAND_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* This is a PRNG for non-cryptographic use.
|
||||
*
|
||||
* See:
|
||||
* https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Sets the seed for the PRNG.
|
||||
*
|
||||
* @param s The specific seed value or zero. If zero is passed, it will call
|
||||
* rand_reseed().
|
||||
*/
|
||||
void sbadrand(uint64_t s);
|
||||
|
||||
/**
|
||||
* @brief Generates a pseudo-random 64-bit number.
|
||||
*
|
||||
* Uses a simple Linear Congruential Generator (LCG) to produce
|
||||
* a sequence of pseudo-random numbers.
|
||||
*
|
||||
* @return A pseudo-random 64-bit unsigned integer.
|
||||
*/
|
||||
uint64_t badrand();
|
||||
|
||||
/**
|
||||
* @brief Generates a random number within a specified range.
|
||||
*
|
||||
* Produces a random number in the inclusive range [min, max].
|
||||
* Ensures uniform distribution by applying a modulo operation.
|
||||
*
|
||||
* @param min The lower bound of the range (inclusive).
|
||||
* @param max The upper bound of the range (inclusive).
|
||||
* @return A random number between min and max.
|
||||
*/
|
||||
uint64_t badrand_range(uint64_t min, uint64_t max);
|
||||
|
||||
#endif // BADRAND_H
|
|
@ -1,139 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <buddy.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_ORDER 22 // 2^22 * min_block_size = max allocatable block
|
||||
#define MIN_BLOCK_SIZE 32 // Smallest allocatable block
|
||||
|
||||
typedef struct free_block {
|
||||
struct free_block *next;
|
||||
} free_block_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t order;
|
||||
} block_header_t;
|
||||
|
||||
static free_block_t *free_lists[MAX_ORDER + 1];
|
||||
|
||||
uintptr_t heap_start = (uintptr_t)&__heap_start;
|
||||
uintptr_t heap_end = (uintptr_t)&__heap_end;
|
||||
|
||||
// Utility: round up to next power of two
|
||||
static size_t next_pow2(size_t x) {
|
||||
if (x <= 1)
|
||||
return 1;
|
||||
x--;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
#if UINTPTR_MAX > 0xffffffff
|
||||
x |= x >> 32;
|
||||
#endif
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
// Find order for size
|
||||
static int size_to_order(size_t size) {
|
||||
size_t needed = (size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : size;
|
||||
size_t block_size = next_pow2(needed);
|
||||
int order = 0;
|
||||
while ((MIN_BLOCK_SIZE << order) < block_size) {
|
||||
order++;
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
// Initialize allocator
|
||||
void buddy_init(uintptr_t start, uintptr_t end) {
|
||||
heap_start = (start + MIN_BLOCK_SIZE - 1) & ~(MIN_BLOCK_SIZE - 1);
|
||||
heap_end = end & ~(MIN_BLOCK_SIZE - 1);
|
||||
|
||||
// Clear free lists
|
||||
for (int i = 0; i <= MAX_ORDER; i++) free_lists[i] = NULL;
|
||||
|
||||
// Put the whole region as one big block
|
||||
size_t total_size = heap_end - heap_start;
|
||||
int order = MAX_ORDER;
|
||||
while ((MIN_BLOCK_SIZE << order) > total_size && order > 0) order--;
|
||||
|
||||
free_block_t *block = (free_block_t *)heap_start;
|
||||
block->next = NULL;
|
||||
free_lists[order] = block;
|
||||
}
|
||||
|
||||
// Allocate memory
|
||||
void *buddy_alloc(size_t size) {
|
||||
int order = size_to_order(size);
|
||||
|
||||
for (int i = order; i <= MAX_ORDER; i++) {
|
||||
if (free_lists[i]) {
|
||||
// Remove block from this list
|
||||
free_block_t *block = free_lists[i];
|
||||
free_lists[i] = block->next;
|
||||
|
||||
// Split down to requested order
|
||||
while (i > order) {
|
||||
i--;
|
||||
uintptr_t buddy_addr = (uintptr_t)block + (MIN_BLOCK_SIZE << i);
|
||||
free_block_t *buddy = (free_block_t *)buddy_addr;
|
||||
buddy->next = free_lists[i];
|
||||
free_lists[i] = buddy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here, we install a header into the block. This will allow us to use free, without
|
||||
* specifying size, since it can read the order from one byte before the block start.
|
||||
*/
|
||||
{
|
||||
block_header_t *hdr = (block_header_t *)block;
|
||||
hdr->order = order;
|
||||
return (void *)(hdr + 1); // return pointer after header
|
||||
// return (void *)block; // Regular block return for reference
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL; // Out of memory
|
||||
}
|
||||
|
||||
// Free memory
|
||||
int buddy_free(void *ptr) {
|
||||
block_header_t *hdr = (block_header_t *)ptr - 1;
|
||||
int order = hdr->order;
|
||||
|
||||
assert_msg(order != MAX_ORDER, "The buddy freelist header seems to have been corrupted.");
|
||||
|
||||
uintptr_t addr = (uintptr_t)ptr;
|
||||
|
||||
while (order < MAX_ORDER) {
|
||||
uintptr_t buddy_addr = addr ^ (MIN_BLOCK_SIZE << order);
|
||||
|
||||
// Check if buddy is in free list
|
||||
free_block_t **prev = &free_lists[order];
|
||||
free_block_t *cur = free_lists[order];
|
||||
while (cur) {
|
||||
if ((uintptr_t)cur == buddy_addr) {
|
||||
// Remove buddy from list
|
||||
*prev = cur->next;
|
||||
// Merge
|
||||
if (buddy_addr < addr)
|
||||
addr = buddy_addr;
|
||||
order++;
|
||||
goto try_merge;
|
||||
}
|
||||
prev = &cur->next;
|
||||
cur = cur->next;
|
||||
}
|
||||
break; // Buddy not free, stop
|
||||
try_merge:;
|
||||
}
|
||||
|
||||
free_block_t *block = (free_block_t *)addr;
|
||||
block->next = free_lists[order];
|
||||
free_lists[order] = block;
|
||||
|
||||
return order;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef BUDDY_H
|
||||
#define BUDDY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern uintptr_t heap_start;
|
||||
extern uintptr_t heap_end;
|
||||
|
||||
extern char __heap_start;
|
||||
extern char __heap_end;
|
||||
|
||||
void buddy_init(uintptr_t start, uintptr_t end);
|
||||
void *buddy_alloc(size_t size);
|
||||
int buddy_free(void *ptr);
|
||||
|
||||
/* Returns total heap memory managed by buddy allocator in bytes */
|
||||
static inline size_t buddy_total_bytes(void) {
|
||||
return (uintptr_t)&__heap_end - (uintptr_t)&__heap_start;
|
||||
}
|
||||
|
||||
#endif // BUDDY_H
|
|
@ -1,136 +1,91 @@
|
|||
#ifndef ENDIAN_KERNEL_H
|
||||
#define ENDIAN_KERNEL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <types.h>
|
||||
|
||||
/** Swap byte order of 16-bit value */
|
||||
static inline u16 swap16(u16 x) {
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
static inline u16 swap16(u16 x) { return (x >> 8) | (x << 8); }
|
||||
|
||||
/** Swap byte order of 32-bit value */
|
||||
static inline u32 swap32(u32 x) {
|
||||
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) | ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
||||
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) |
|
||||
((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
||||
}
|
||||
|
||||
/** Swap byte order of 64-bit value */
|
||||
static inline u64 swap64(u64 x) {
|
||||
return ((x >> 56) & 0x00000000000000ffULL) | ((x >> 40) & 0x000000000000ff00ULL) |
|
||||
((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 8) & 0x00000000ff000000ULL) |
|
||||
((x << 8) & 0x000000ff00000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) |
|
||||
((x << 40) & 0x00ff000000000000ULL) | ((x << 56) & 0xff00000000000000ULL);
|
||||
return ((x >> 56) & 0x00000000000000ffULL) |
|
||||
((x >> 40) & 0x000000000000ff00ULL) |
|
||||
((x >> 24) & 0x0000000000ff0000ULL) |
|
||||
((x >> 8) & 0x00000000ff000000ULL) |
|
||||
((x << 8) & 0x000000ff00000000ULL) |
|
||||
((x << 24) & 0x0000ff0000000000ULL) |
|
||||
((x << 40) & 0x00ff000000000000ULL) |
|
||||
((x << 56) & 0xff00000000000000ULL);
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
/** Convert 16-bit value to little-endian */
|
||||
static inline u16 to_le16(u16 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u16 to_le16(u16 x) { return x; }
|
||||
/** Convert 16-bit little-endian value to host */
|
||||
static inline u16 from_le16(u16 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u16 from_le16(u16 x) { return x; }
|
||||
|
||||
/** Convert 32-bit value to little-endian */
|
||||
static inline u32 to_le32(u32 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u32 to_le32(u32 x) { return x; }
|
||||
/** Convert 32-bit little-endian value to host */
|
||||
static inline u32 from_le32(u32 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u32 from_le32(u32 x) { return x; }
|
||||
|
||||
/** Convert 64-bit value to little-endian */
|
||||
static inline u64 to_le64(u64 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u64 to_le64(u64 x) { return x; }
|
||||
/** Convert 64-bit little-endian value to host */
|
||||
static inline u64 from_le64(u64 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u64 from_le64(u64 x) { return x; }
|
||||
|
||||
/** Convert 16-bit value to big-endian */
|
||||
static inline u16 to_be16(u16 x) {
|
||||
return swap16(x);
|
||||
}
|
||||
static inline u16 to_be16(u16 x) { return swap16(x); }
|
||||
/** Convert 16-bit big-endian value to host */
|
||||
static inline u16 from_be16(u16 x) {
|
||||
return swap16(x);
|
||||
}
|
||||
static inline u16 from_be16(u16 x) { return swap16(x); }
|
||||
|
||||
/** Convert 32-bit value to big-endian */
|
||||
static inline u32 to_be32(u32 x) {
|
||||
return swap32(x);
|
||||
}
|
||||
static inline u32 to_be32(u32 x) { return swap32(x); }
|
||||
/** Convert 32-bit big-endian value to host */
|
||||
static inline u32 from_be32(u32 x) {
|
||||
return swap32(x);
|
||||
}
|
||||
static inline u32 from_be32(u32 x) { return swap32(x); }
|
||||
|
||||
/** Convert 64-bit value to big-endian */
|
||||
static inline u64 to_be64(u64 x) {
|
||||
return swap64(x);
|
||||
}
|
||||
static inline u64 to_be64(u64 x) { return swap64(x); }
|
||||
/** Convert 64-bit big-endian value to host */
|
||||
static inline u64 from_be64(u64 x) {
|
||||
return swap64(x);
|
||||
}
|
||||
static inline u64 from_be64(u64 x) { return swap64(x); }
|
||||
|
||||
#else // Big-endian
|
||||
|
||||
/** Convert 16-bit value to little-endian */
|
||||
static inline u16 to_le16(u16 x) {
|
||||
return swap16(x);
|
||||
}
|
||||
static inline u16 to_le16(u16 x) { return swap16(x); }
|
||||
/** Convert 16-bit little-endian value to host */
|
||||
static inline u16 from_le16(u16 x) {
|
||||
return swap16(x);
|
||||
}
|
||||
static inline u16 from_le16(u16 x) { return swap16(x); }
|
||||
|
||||
/** Convert 32-bit value to little-endian */
|
||||
static inline u32 to_le32(u32 x) {
|
||||
return swap32(x);
|
||||
}
|
||||
static inline u32 to_le32(u32 x) { return swap32(x); }
|
||||
/** Convert 32-bit little-endian value to host */
|
||||
static inline u32 from_le32(u32 x) {
|
||||
return swap32(x);
|
||||
}
|
||||
static inline u32 from_le32(u32 x) { return swap32(x); }
|
||||
|
||||
/** Convert 64-bit value to little-endian */
|
||||
static inline u64 to_le64(u64 x) {
|
||||
return swap64(x);
|
||||
}
|
||||
static inline u64 to_le64(u64 x) { return swap64(x); }
|
||||
/** Convert 64-bit little-endian value to host */
|
||||
static inline u64 from_le64(u64 x) {
|
||||
return swap64(x);
|
||||
}
|
||||
static inline u64 from_le64(u64 x) { return swap64(x); }
|
||||
|
||||
/** Convert 16-bit value to big-endian */
|
||||
static inline u16 to_be16(u16 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u16 to_be16(u16 x) { return x; }
|
||||
/** Convert 16-bit big-endian value to host */
|
||||
static inline u16 from_be16(u16 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u16 from_be16(u16 x) { return x; }
|
||||
|
||||
/** Convert 32-bit value to big-endian */
|
||||
static inline u32 to_be32(u32 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u32 to_be32(u32 x) { return x; }
|
||||
/** Convert 32-bit big-endian value to host */
|
||||
static inline u32 from_be32(u32 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u32 from_be32(u32 x) { return x; }
|
||||
|
||||
/** Convert 64-bit value to big-endian */
|
||||
static inline u64 to_be64(u64 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u64 to_be64(u64 x) { return x; }
|
||||
/** Convert 64-bit big-endian value to host */
|
||||
static inline u64 from_be64(u64 x) {
|
||||
return x;
|
||||
}
|
||||
static inline u64 from_be64(u64 x) { return x; }
|
||||
|
||||
#endif // __LITTLE_ENDIAN__
|
||||
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
#include "freelist.h"
|
||||
#include "stddef.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct FreeListBlock {
|
||||
struct FreeListBlock *next;
|
||||
};
|
||||
|
||||
/* Initialize the FreeList */
|
||||
int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize) {
|
||||
size_t size = ALIGN(itemsize);
|
||||
|
||||
if (!fl || end <= start)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
fl->start = start;
|
||||
fl->end = end;
|
||||
fl->size = size;
|
||||
fl->allocated = 0;
|
||||
|
||||
FreeListBlock *block = (FreeListBlock *)start;
|
||||
for (size_t i = 0; i < fl_capacity(fl); i++) {
|
||||
block->next = (FreeListBlock *)((void *)block + size);
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
block->next = NULL;
|
||||
|
||||
fl->free = (FreeListBlock *)start;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Allocate some memory from the FreeList */
|
||||
void *fl_alloc(FreeList *fl) {
|
||||
if (!fl->free)
|
||||
return NULL;
|
||||
|
||||
FreeListBlock *m = fl->free;
|
||||
|
||||
fl->free = fl->free->next;
|
||||
fl->allocated++;
|
||||
|
||||
memset((void *)m, 0, sizeof(FreeListBlock));
|
||||
return ((void *)m);
|
||||
}
|
||||
|
||||
/* Return some memory to the FreeList */
|
||||
int fl_free(FreeList *fl, void *ptr) {
|
||||
if (!fl_is_managed(fl, ptr)) {
|
||||
return EXIT_FAILURE; /* We cant free memory we do not own */
|
||||
}
|
||||
|
||||
FreeListBlock *block = (FreeListBlock *)(uintptr_t)ptr;
|
||||
|
||||
block->next = fl->free;
|
||||
fl->free = block;
|
||||
fl->allocated--;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Returns how many slots are occupied */
|
||||
size_t fl_allocated(FreeList *fl) {
|
||||
return fl->allocated;
|
||||
}
|
||||
|
||||
/* Returns how many free slots are available (O(1)) */
|
||||
size_t fl_available(FreeList *fl) {
|
||||
return fl_capacity(fl) - fl->allocated;
|
||||
}
|
||||
|
||||
/* Returns the total amount of items the freelist will hold */
|
||||
size_t fl_capacity(FreeList *fl) {
|
||||
return (fl->end - fl->start) / fl->size;
|
||||
}
|
||||
|
||||
/* Check if a piece of memory is managed by the FreeList */
|
||||
int fl_is_managed(FreeList *fl, void *ptr) {
|
||||
return ((uintptr_t)ptr >= fl->start && (uintptr_t)ptr < fl->end);
|
||||
}
|
||||
|
||||
/* Returns the ratio of metadata versus data as a scalar in range 0..1 */
|
||||
float fl_utilization(FreeList *fl, size_t itemsize) {
|
||||
return (float)itemsize / fl->size;
|
||||
}
|
||||
|
||||
/* Walks the free pages/slots, returns total count (O(n), given no cycles) */
|
||||
size_t fl_check(FreeList *fl) {
|
||||
int avail = 0;
|
||||
FreeListBlock *cursor = fl->free;
|
||||
|
||||
while (cursor->next != NULL) {
|
||||
avail++;
|
||||
cursor = cursor->next;
|
||||
}
|
||||
|
||||
return avail;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#ifndef FREELIST_H
|
||||
#define FREELIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Align to nearest multiple of align */
|
||||
static inline size_t align_up_to(size_t n, size_t align) {
|
||||
return (n + align - 1) & ~(align - 1);
|
||||
}
|
||||
|
||||
/* Fiddle these around according to your need. Delete or check makefile */
|
||||
#ifdef FREELIST_ALIGN
|
||||
#define ALIGN(x) (align_up_to(x, sizeof(void *)))
|
||||
#else
|
||||
#define ALIGN(x) (x)
|
||||
#endif
|
||||
|
||||
typedef struct FreeListBlock FreeListBlock;
|
||||
|
||||
typedef struct {
|
||||
FreeListBlock *free;
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
size_t size;
|
||||
size_t allocated;
|
||||
} FreeList;
|
||||
|
||||
int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize);
|
||||
int fl_free(FreeList *fl, void *ptr);
|
||||
int fl_is_managed(FreeList *fl, void *ptr);
|
||||
void *fl_alloc(FreeList *fl);
|
||||
size_t fl_check(FreeList *fl);
|
||||
size_t fl_allocated(FreeList *fl);
|
||||
size_t fl_available(FreeList *fl);
|
||||
size_t fl_capacity(FreeList *fl);
|
||||
float fl_utilization(FreeList *fl, size_t itemsize);
|
||||
|
||||
#endif // FREELIST_H
|
|
@ -1,21 +1,29 @@
|
|||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uart.h>
|
||||
|
||||
int memory_sweep(const uintptr_t start, const uintptr_t end) {
|
||||
assert_msg(start < end, "Start needs to be before end.");
|
||||
uintptr_t sweeper = start;
|
||||
#define MAX_PROBE_SIZE (256 * 1024 * 1024) // Probe up to 256 MiB max
|
||||
#define PROBE_STEP 0x1000 // Probe every 4 KiB page
|
||||
|
||||
while (sweeper < end) {
|
||||
*(uint64_t *)sweeper = 0xFAFAFAFABCBCBCBC;
|
||||
sweeper += sizeof(uint64_t);
|
||||
size_t probe_memory(void) {
|
||||
volatile u32 *addr;
|
||||
u32 test_pattern = 0xA5A5A5A5;
|
||||
size_t detected = 0;
|
||||
|
||||
for (size_t offset = 4096 * 16; offset < MAX_PROBE_SIZE;
|
||||
offset += PROBE_STEP) {
|
||||
addr = (volatile u32 *)(KERNBASE + offset);
|
||||
|
||||
u32 old = *addr;
|
||||
*addr = test_pattern;
|
||||
|
||||
if (*addr != test_pattern) {
|
||||
break; // Memory not readable/writable here, stop probing
|
||||
}
|
||||
|
||||
*addr = old; // restore original data
|
||||
detected = offset + PROBE_STEP;
|
||||
}
|
||||
|
||||
sweeper -= sizeof(uint64_t);
|
||||
while (sweeper != start) {
|
||||
assert(*(uint64_t *)sweeper == 0xFAFAFAFABCBCBCBC);
|
||||
sweeper -= sizeof(uint64_t);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return detected;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
#define PHYSTOP (KERNBASE + 128 * 1024 * 1024)
|
||||
|
||||
/**
|
||||
* Set and fetch routine for checking memory.
|
||||
* Returns size in bytes of detected RAM In qemu, it requires a trap handler to
|
||||
* handle the interrupt when accessing unavailable memory.
|
||||
*/
|
||||
int memory_sweep(const uintptr_t start, const uintptr_t end);
|
||||
size_t probe_memory(void);
|
||||
|
||||
#endif // MEMORY_KERNEL_H
|
||||
#endif
|
||||
|
|
|
@ -43,251 +43,269 @@
|
|||
|
||||
#include "mini-printf.h"
|
||||
|
||||
static int mini_strlen(const char *s) {
|
||||
int len = 0;
|
||||
while (s[len] != '\0') len++;
|
||||
return len;
|
||||
static int
|
||||
mini_strlen(const char *s)
|
||||
{
|
||||
int len = 0;
|
||||
while (s[len] != '\0') len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int mini_itoa(long value, unsigned int radix, int uppercase, int unsig, char *buffer) {
|
||||
char *pbuffer = buffer;
|
||||
int negative = 0;
|
||||
int i, len;
|
||||
static int
|
||||
mini_itoa(long value, unsigned int radix, int uppercase, int unsig,
|
||||
char *buffer)
|
||||
{
|
||||
char *pbuffer = buffer;
|
||||
int negative = 0;
|
||||
int i, len;
|
||||
|
||||
/* No support for unusual radixes. */
|
||||
if (radix > 16)
|
||||
return 0;
|
||||
/* No support for unusual radixes. */
|
||||
if (radix > 16)
|
||||
return 0;
|
||||
|
||||
if (value < 0 && !unsig) {
|
||||
negative = 1;
|
||||
value = -value;
|
||||
}
|
||||
if (value < 0 && !unsig) {
|
||||
negative = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
/* This builds the string back to front ... */
|
||||
do {
|
||||
int digit = value % radix;
|
||||
*(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10);
|
||||
value /= radix;
|
||||
} while (value > 0);
|
||||
/* This builds the string back to front ... */
|
||||
do {
|
||||
int digit = value % radix;
|
||||
*(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10);
|
||||
value /= radix;
|
||||
} while (value > 0);
|
||||
|
||||
if (negative)
|
||||
*(pbuffer++) = '-';
|
||||
if (negative)
|
||||
*(pbuffer++) = '-';
|
||||
|
||||
*(pbuffer) = '\0';
|
||||
*(pbuffer) = '\0';
|
||||
|
||||
/* ... now we reverse it (could do it recursively but will
|
||||
* conserve the stack space) */
|
||||
len = (pbuffer - buffer);
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
char j = buffer[i];
|
||||
buffer[i] = buffer[len - i - 1];
|
||||
buffer[len - i - 1] = j;
|
||||
}
|
||||
/* ... now we reverse it (could do it recursively but will
|
||||
* conserve the stack space) */
|
||||
len = (pbuffer - buffer);
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
char j = buffer[i];
|
||||
buffer[i] = buffer[len-i-1];
|
||||
buffer[len-i-1] = j;
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int mini_pad(char *ptr, int len, char pad_char, int pad_to, char *buffer) {
|
||||
int i;
|
||||
int overflow = 0;
|
||||
char *pbuffer = buffer;
|
||||
if (pad_to == 0)
|
||||
pad_to = len;
|
||||
if (len > pad_to) {
|
||||
len = pad_to;
|
||||
overflow = 1;
|
||||
}
|
||||
for (i = pad_to - len; i > 0; i--) {
|
||||
*(pbuffer++) = pad_char;
|
||||
}
|
||||
for (i = len; i > 0; i--) {
|
||||
*(pbuffer++) = *(ptr++);
|
||||
}
|
||||
len = pbuffer - buffer;
|
||||
if (overflow) {
|
||||
for (i = 0; i < 3 && pbuffer > buffer; i++) {
|
||||
*(pbuffer-- - 1) = '*';
|
||||
}
|
||||
}
|
||||
return len;
|
||||
static int
|
||||
mini_pad(char* ptr, int len, char pad_char, int pad_to, char *buffer)
|
||||
{
|
||||
int i;
|
||||
int overflow = 0;
|
||||
char * pbuffer = buffer;
|
||||
if(pad_to == 0) pad_to = len;
|
||||
if(len > pad_to) {
|
||||
len = pad_to;
|
||||
overflow = 1;
|
||||
}
|
||||
for(i = pad_to - len; i > 0; i --) {
|
||||
*(pbuffer++) = pad_char;
|
||||
}
|
||||
for(i = len; i > 0; i --) {
|
||||
*(pbuffer++) = *(ptr++);
|
||||
}
|
||||
len = pbuffer - buffer;
|
||||
if(overflow) {
|
||||
for (i = 0; i < 3 && pbuffer > buffer; i ++) {
|
||||
*(pbuffer-- - 1) = '*';
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
struct mini_buff {
|
||||
char *buffer, *pbuffer;
|
||||
unsigned int buffer_len;
|
||||
char *buffer, *pbuffer;
|
||||
unsigned int buffer_len;
|
||||
};
|
||||
|
||||
static int _puts(char *s, int len, void *buf) {
|
||||
if (!buf)
|
||||
return len;
|
||||
struct mini_buff *b = buf;
|
||||
char *p0 = b->buffer;
|
||||
int i;
|
||||
/* Copy to buffer */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (b->pbuffer == b->buffer + b->buffer_len - 1) {
|
||||
break;
|
||||
}
|
||||
*(b->pbuffer++) = s[i];
|
||||
}
|
||||
*(b->pbuffer) = 0;
|
||||
return b->pbuffer - p0;
|
||||
static int
|
||||
_puts(char *s, int len, void *buf)
|
||||
{
|
||||
if(!buf) return len;
|
||||
struct mini_buff *b = buf;
|
||||
char * p0 = b->buffer;
|
||||
int i;
|
||||
/* Copy to buffer */
|
||||
for (i = 0; i < len; i++) {
|
||||
if(b->pbuffer == b->buffer + b->buffer_len - 1) {
|
||||
break;
|
||||
}
|
||||
*(b->pbuffer ++) = s[i];
|
||||
}
|
||||
*(b->pbuffer) = 0;
|
||||
return b->pbuffer - p0;
|
||||
}
|
||||
|
||||
#ifdef MINI_PRINTF_ENABLE_OBJECTS
|
||||
static int (*mini_handler)(void *data, void *obj, int ch, int lhint, char **bf) = 0;
|
||||
static void (*mini_handler_freeor)(void *data, void *) = 0;
|
||||
static void *mini_handler_data = 0;
|
||||
static int (*mini_handler) (void* data, void* obj, int ch, int lhint, char** bf) = 0;
|
||||
static void (*mini_handler_freeor)(void* data, void*) = 0;
|
||||
static void * mini_handler_data = 0;
|
||||
|
||||
void mini_printf_set_handler(void *data, int (*handler)(void *data, void *obj, int ch, int len_hint, char **buf),
|
||||
void (*freeor)(void *data, void *buf)) {
|
||||
mini_handler = handler;
|
||||
mini_handler_freeor = freeor;
|
||||
mini_handler_data = data;
|
||||
void mini_printf_set_handler(
|
||||
void* data,
|
||||
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
|
||||
void (*freeor)(void* data, void* buf))
|
||||
{
|
||||
mini_handler = handler;
|
||||
mini_handler_freeor = freeor;
|
||||
mini_handler_data = data;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va) {
|
||||
struct mini_buff b;
|
||||
b.buffer = buffer;
|
||||
b.pbuffer = buffer;
|
||||
b.buffer_len = buffer_len;
|
||||
if (buffer_len == 0)
|
||||
buffer = (void *)0;
|
||||
int n = mini_vpprintf(_puts, (buffer != (void *)0) ? &b : (void *)0, fmt, va);
|
||||
if (buffer == (void *)0) {
|
||||
return n;
|
||||
}
|
||||
return b.pbuffer - b.buffer;
|
||||
int
|
||||
mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va)
|
||||
{
|
||||
struct mini_buff b;
|
||||
b.buffer = buffer;
|
||||
b.pbuffer = buffer;
|
||||
b.buffer_len = buffer_len;
|
||||
if(buffer_len == 0) buffer = (void*) 0;
|
||||
int n = mini_vpprintf(_puts, (buffer != (void*)0)?&b:(void*)0, fmt, va);
|
||||
if(buffer == (void*) 0) {
|
||||
return n;
|
||||
}
|
||||
return b.pbuffer - b.buffer;
|
||||
}
|
||||
|
||||
int mini_vpprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, va_list va) {
|
||||
char bf[24];
|
||||
char bf2[24];
|
||||
char ch;
|
||||
int
|
||||
mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va)
|
||||
{
|
||||
char bf[24];
|
||||
char bf2[24];
|
||||
char ch;
|
||||
#ifdef MINI_PRINTF_ENABLE_OBJECTS
|
||||
void *obj;
|
||||
void* obj;
|
||||
#endif
|
||||
if (puts == (void *)0) {
|
||||
/* run puts in counting mode. */
|
||||
puts = _puts;
|
||||
buf = (void *)0;
|
||||
}
|
||||
int n = 0;
|
||||
while ((ch = *(fmt++))) {
|
||||
int len;
|
||||
if (ch != '%') {
|
||||
len = 1;
|
||||
len = puts(&ch, len, buf);
|
||||
} else {
|
||||
char pad_char = ' ';
|
||||
int pad_to = 0;
|
||||
char l = 0;
|
||||
char *ptr;
|
||||
if(puts == (void*)0) {
|
||||
/* run puts in counting mode. */
|
||||
puts = _puts; buf = (void*)0;
|
||||
}
|
||||
int n = 0;
|
||||
while ((ch=*(fmt++))) {
|
||||
int len;
|
||||
if (ch!='%') {
|
||||
len = 1;
|
||||
len = puts(&ch, len, buf);
|
||||
} else {
|
||||
char pad_char = ' ';
|
||||
int pad_to = 0;
|
||||
char l = 0;
|
||||
char *ptr;
|
||||
|
||||
ch = *(fmt++);
|
||||
ch=*(fmt++);
|
||||
|
||||
/* Zero padding requested */
|
||||
if (ch == '0')
|
||||
pad_char = '0';
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
pad_to = pad_to * 10 + (ch - '0');
|
||||
ch = *(fmt++);
|
||||
}
|
||||
if (pad_to > (signed int)sizeof(bf)) {
|
||||
pad_to = sizeof(bf);
|
||||
}
|
||||
if (ch == 'l') {
|
||||
l = 1;
|
||||
ch = *(fmt++);
|
||||
}
|
||||
/* Zero padding requested */
|
||||
if (ch == '0') pad_char = '0';
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
pad_to = pad_to * 10 + (ch - '0');
|
||||
ch=*(fmt++);
|
||||
}
|
||||
if(pad_to > (signed int) sizeof(bf)) {
|
||||
pad_to = sizeof(bf);
|
||||
}
|
||||
if (ch == 'l') {
|
||||
l = 1;
|
||||
ch=*(fmt++);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case 0: goto end;
|
||||
case 'u':
|
||||
case 'd':
|
||||
if (l) {
|
||||
len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch == 'u'), bf2);
|
||||
} else {
|
||||
if (ch == 'u') {
|
||||
len = mini_itoa((unsigned long)va_arg(va, unsigned int), 10, 0, 1, bf2);
|
||||
} else {
|
||||
len = mini_itoa((long)va_arg(va, int), 10, 0, 0, bf2);
|
||||
}
|
||||
}
|
||||
len = mini_pad(bf2, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
switch (ch) {
|
||||
case 0:
|
||||
goto end;
|
||||
case 'u':
|
||||
case 'd':
|
||||
if(l) {
|
||||
len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch=='u'), bf2);
|
||||
} else {
|
||||
if(ch == 'u') {
|
||||
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 10, 0, 1, bf2);
|
||||
} else {
|
||||
len = mini_itoa((long) va_arg(va, int), 10, 0, 0, bf2);
|
||||
}
|
||||
}
|
||||
len = mini_pad(bf2, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (l) {
|
||||
len = mini_itoa(va_arg(va, unsigned long), 16, (ch == 'X'), 1, bf2);
|
||||
} else {
|
||||
len = mini_itoa((unsigned long)va_arg(va, unsigned int), 16, (ch == 'X'), 1, bf2);
|
||||
}
|
||||
len = mini_pad(bf2, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
if(l) {
|
||||
len = mini_itoa(va_arg(va, unsigned long), 16, (ch=='X'), 1, bf2);
|
||||
} else {
|
||||
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 16, (ch=='X'), 1, bf2);
|
||||
}
|
||||
len = mini_pad(bf2, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ch = (char)(va_arg(va, int));
|
||||
len = mini_pad(&ch, 1, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
case 'c' :
|
||||
ch = (char)(va_arg(va, int));
|
||||
len = mini_pad(&ch, 1, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
ptr = va_arg(va, char *);
|
||||
len = mini_strlen(ptr);
|
||||
if (pad_to > 0) {
|
||||
len = mini_pad(ptr, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
} else {
|
||||
len = puts(ptr, len, buf);
|
||||
}
|
||||
break;
|
||||
case 's' :
|
||||
ptr = va_arg(va, char*);
|
||||
len = mini_strlen(ptr);
|
||||
if (pad_to > 0) {
|
||||
len = mini_pad(ptr, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
} else {
|
||||
len = puts(ptr, len, buf);
|
||||
}
|
||||
break;
|
||||
#ifdef MINI_PRINTF_ENABLE_OBJECTS
|
||||
case 'O': /* Object by content (e.g. str) */
|
||||
case 'R': /* Object by representation (e.g. repr)*/
|
||||
obj = va_arg(va, void *);
|
||||
len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr);
|
||||
if (pad_to > 0) {
|
||||
len = mini_pad(ptr, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
} else {
|
||||
len = puts(ptr, len, buf);
|
||||
}
|
||||
mini_handler_freeor(mini_handler_data, ptr);
|
||||
break;
|
||||
case 'O' : /* Object by content (e.g. str) */
|
||||
case 'R' : /* Object by representation (e.g. repr)*/
|
||||
obj = va_arg(va, void*);
|
||||
len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr);
|
||||
if (pad_to > 0) {
|
||||
len = mini_pad(ptr, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
} else {
|
||||
len = puts(ptr, len, buf);
|
||||
}
|
||||
mini_handler_freeor(mini_handler_data, ptr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
len = 1;
|
||||
len = puts(&ch, len, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
n = n + len;
|
||||
}
|
||||
default:
|
||||
len = 1;
|
||||
len = puts(&ch, len, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
n = n + len;
|
||||
}
|
||||
end:
|
||||
return n;
|
||||
return n;
|
||||
}
|
||||
|
||||
int mini_snprintf(char *buffer, unsigned int buffer_len, const char *fmt, ...) {
|
||||
int ret;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ret = mini_vsnprintf(buffer, buffer_len, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return ret;
|
||||
int
|
||||
mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ret = mini_vsnprintf(buffer, buffer_len, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mini_pprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, ...) {
|
||||
int ret;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ret = mini_vpprintf(puts, buf, fmt, va);
|
||||
va_end(va);
|
||||
int
|
||||
mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ret = mini_vpprintf(puts, buf, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MINI_PRINTF__
|
||||
#define __MINI_PRINTF__
|
||||
|
||||
|
@ -41,31 +42,32 @@ extern "C" {
|
|||
* void* arguments matching %O and %R are sent to handler as obj.
|
||||
* the result string created by handler at *buf is freed by freeor.
|
||||
* */
|
||||
void mini_printf_set_handler(void *data,
|
||||
/* handler returns number of chars in *buf; *buf is not NUL-terminated. */
|
||||
int (*handler)(void *data, void *obj, int ch, int len_hint, char **buf),
|
||||
void (*freeor)(void *data, void *buf));
|
||||
void mini_printf_set_handler(
|
||||
void * data,
|
||||
/* handler returns number of chars in *buf; *buf is not NUL-terminated. */
|
||||
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
|
||||
void (*freeor)(void* data, void* buf));
|
||||
#endif
|
||||
|
||||
/* String IO interface; returns number of bytes written, not including the ending NUL.
|
||||
* Always appends a NUL at the end, therefore buffer_len shall be at least 1 in normal operation.
|
||||
* If buffer is NULL or buffer_len is 0, returns number of bytes to be written, not including the ending NUL.
|
||||
*/
|
||||
int mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va);
|
||||
int mini_snprintf(char *buffer, unsigned int buffer_len, const char *fmt, ...);
|
||||
int mini_vsnprintf(char* buffer, unsigned int buffer_len, const char *fmt, va_list va);
|
||||
int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...);
|
||||
|
||||
/* Stream IO interface; returns number of bytes written.
|
||||
* If puts is NULL, number of bytes to be written.
|
||||
* puts shall return number of bytes written.
|
||||
*/
|
||||
int mini_vpprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, va_list va);
|
||||
int mini_pprintf(int (*puts)(char *s, int len, void *buf), void *buf, const char *fmt, ...);
|
||||
int mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va);
|
||||
int mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define vsnprintf mini_vsnprintf
|
||||
#define snprintf mini_snprintf
|
||||
#define snprintf mini_snprintf
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
#include "stdbool.h"
|
||||
#include <mini-printf.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <uart.h>
|
||||
volatile int panicked;
|
||||
|
||||
volatile int panicked = false;
|
||||
|
||||
__attribute__((visibility("hidden"))) void __panic(const char *restrict fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
kvprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
panicked = true;
|
||||
for (;;) asm volatile("wfi");
|
||||
void panic(char *s) {
|
||||
panicked = 1;
|
||||
uart_puts(s);
|
||||
while (1);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef KERNEL_PANIC_H
|
||||
#define KERNEL_PANIC_H
|
||||
|
||||
#define PANIC(fmt, ...) __panic("[Panic @ %s:%d %s] " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
|
||||
void panic(char *s);
|
||||
|
||||
void __panic(const char *restrict fmt, ...);
|
||||
|
||||
#endif // KERNEL_PANIC_H
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <proc.h>
|
||||
|
||||
Cpu cpus[NCPU];
|
||||
struct Cpu cpus[NCPU];
|
||||
|
||||
/**
|
||||
* Must be called with interrupts disabled, to prevent race with process being
|
||||
|
@ -14,8 +14,8 @@ int cpuid() {
|
|||
/**
|
||||
* Return this CPU's cpu struct. Interrupts must be disabled.
|
||||
*/
|
||||
Cpu *mycpu(void) {
|
||||
int id = cpuid();
|
||||
Cpu *c = &cpus[id];
|
||||
struct Cpu *mycpu(void) {
|
||||
int id = cpuid();
|
||||
struct Cpu *c = &cpus[id];
|
||||
return c;
|
||||
}
|
||||
|
|
|
@ -39,9 +39,7 @@ static inline u64 read_tp() {
|
|||
}
|
||||
|
||||
/** Write thread pointer */
|
||||
static inline void write_tp(u64 x) {
|
||||
asm volatile("mv tp, %0" : : "r"(x));
|
||||
}
|
||||
static inline void write_tp(u64 x) { asm volatile("mv tp, %0" : : "r"(x)); }
|
||||
|
||||
/**
|
||||
* Read the value of the sstatus register.
|
||||
|
@ -62,14 +60,10 @@ static inline void w_sstatus(u64 x) {
|
|||
}
|
||||
|
||||
/** Enable device interrupts */
|
||||
static inline void intr_on() {
|
||||
w_sstatus(r_sstatus() | SSTATUS_SIE);
|
||||
}
|
||||
static inline void intr_on() { w_sstatus(r_sstatus() | SSTATUS_SIE); }
|
||||
|
||||
/** Disable device interrupts */
|
||||
static inline void intr_off() {
|
||||
w_sstatus(r_sstatus() & ~SSTATUS_SIE);
|
||||
}
|
||||
static inline void intr_off() { w_sstatus(r_sstatus() & ~SSTATUS_SIE); }
|
||||
|
||||
/** Are device interrupts enabled? */
|
||||
static inline int intr_get() {
|
||||
|
@ -77,4 +71,4 @@ static inline int intr_get() {
|
|||
return (x & SSTATUS_SIE) != 0;
|
||||
}
|
||||
|
||||
#endif // RISCV_KERNEL_H
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* (Not mutexes as these are spinning locks).
|
||||
*/
|
||||
|
||||
#include "stddef.h"
|
||||
// #include <lib/stdio.h>
|
||||
#include "string.h"
|
||||
#include <panic.h>
|
||||
#include <proc.h>
|
||||
#include <riscv.h>
|
||||
|
@ -40,95 +41,84 @@
|
|||
* On RISC-V, this emits a fence instruction.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are from the original xv6 implementation, with only slight modifications on their return type.
|
||||
*
|
||||
* push_off/pop_off are like intr_off()/intr_on() except that they are matched:
|
||||
* it takes two pop_off()s to undo two push_off()s. Also, if interrupts
|
||||
* are initially off, then push_off, pop_off leaves them off.
|
||||
/** Initialize Spinlock */
|
||||
void initlock(struct Spinlock *lk, char *name) {
|
||||
lk->name = name;
|
||||
lk->locked = 0;
|
||||
lk->cpu = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire the lock.
|
||||
* Loops (spins) until the lock is acquired.
|
||||
* Panics if the lock is already held by this cpu.
|
||||
*/
|
||||
void acquire(struct Spinlock *lk) {
|
||||
push_off(); // disable interrupts to avoid deadlock.
|
||||
|
||||
uint32_t push_off(void) {
|
||||
int old = intr_get();
|
||||
Cpu *cpu = mycpu();
|
||||
if (holding(lk)) // If the lock is already held, panic.
|
||||
panic("acquire");
|
||||
|
||||
intr_off();
|
||||
// Spin until aquired. See file header for details
|
||||
while (__sync_lock_test_and_set(&lk->locked, 1) != 0);
|
||||
|
||||
if (cpu->noff == 0)
|
||||
cpu->intena = old;
|
||||
__sync_synchronize(); // No loads/stores after this point
|
||||
|
||||
cpu->noff += 1;
|
||||
return cpu->noff;
|
||||
// Record info about lock acquisition for holding() and debugging.
|
||||
lk->cpu = mycpu();
|
||||
}
|
||||
|
||||
uint32_t pop_off(void) {
|
||||
Cpu *cpu = mycpu();
|
||||
/**
|
||||
* Release the lock.
|
||||
* Panics if the lock is not held.
|
||||
*/
|
||||
void release(struct Spinlock *lk) {
|
||||
if (!holding(lk)) // If the lock is not held, panic.
|
||||
panic("release");
|
||||
|
||||
if (intr_get())
|
||||
PANIC("pop_off - interruptible");
|
||||
lk->cpu = 0; // 0 means unheld
|
||||
__sync_synchronize(); // No loads/stores after this point
|
||||
__sync_lock_release(&lk->locked); // Essentially lk->locked = 0
|
||||
|
||||
if (cpu->noff < 1)
|
||||
PANIC("pop_off when cpu->noff < 1");
|
||||
|
||||
cpu->noff -= 1;
|
||||
|
||||
if (cpu->noff == 0 && cpu->intena)
|
||||
intr_on();
|
||||
|
||||
return cpu->noff;
|
||||
}
|
||||
|
||||
void spinlock_init(spinlock_t *l) {
|
||||
l->v = 0;
|
||||
l->cpu = NULL;
|
||||
}
|
||||
|
||||
__attribute__((warn_unused_result)) bool spin_trylock(spinlock_t *l) {
|
||||
uint32_t old;
|
||||
// old = xchg_acquire(&l->v, 1) using AMO
|
||||
__asm__ volatile("amoswap.w.aq %0, %2, (%1)\n" : "=&r"(old) : "r"(&l->v), "r"(1u) : "memory");
|
||||
return old == 0;
|
||||
}
|
||||
|
||||
void spin_unlock(spinlock_t *l) {
|
||||
if (!spin_is_holding(l))
|
||||
PANIC("Unlocking a spinlock that is not held by the locking cpu!");
|
||||
|
||||
/* TODO: Replace with corresponding __atomic builtins */
|
||||
__sync_lock_release(&l->v);
|
||||
__sync_synchronize();
|
||||
|
||||
l->cpu = NULL;
|
||||
pop_off();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test-and-test-and-set acquire with polite spinning + exponential backoff.
|
||||
*/
|
||||
void spin_lock(spinlock_t *l) {
|
||||
uint32_t backoff = 1;
|
||||
for (;;) {
|
||||
if (spin_trylock(l)) {
|
||||
l->cpu = mycpu();
|
||||
push_off();
|
||||
return;
|
||||
}
|
||||
|
||||
while (__atomic_load_n(&l->v, __ATOMIC_RELAXED) != 0) {
|
||||
for (uint32_t i = 0; i < backoff; ++i)
|
||||
__asm__ volatile("nop"); /* NOTE: Pause can be used here if supported */
|
||||
if (backoff < 1u << 12)
|
||||
backoff <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this cpu is holding the lock.
|
||||
* Interrupts must be off.
|
||||
*/
|
||||
bool spin_is_holding(spinlock_t *l) {
|
||||
// Check whether this cpu is holding the lock.
|
||||
// Interrupts must be off.
|
||||
int holding(struct Spinlock *lk) {
|
||||
int r;
|
||||
r = (l->v && l->cpu == mycpu());
|
||||
r = (lk->locked && lk->cpu == mycpu());
|
||||
return r;
|
||||
}
|
||||
|
||||
// push_off/pop_off are like intr_off()/intr_on() except that they are matched:
|
||||
// it takes two pop_off()s to undo two push_off()s. Also, if interrupts
|
||||
// are initially off, then push_off, pop_off leaves them off.
|
||||
|
||||
void push_off(void) {
|
||||
int old = intr_get();
|
||||
|
||||
intr_off();
|
||||
if (mycpu()->noff == 0)
|
||||
mycpu()->intena = old;
|
||||
|
||||
mycpu()->noff += 1;
|
||||
}
|
||||
|
||||
void pop_off(void) {
|
||||
struct Cpu *c = mycpu();
|
||||
if (intr_get())
|
||||
panic("pop_off - interruptible");
|
||||
if (c->noff < 1) {
|
||||
{
|
||||
// TODO: Remove this block when fixed
|
||||
char amt[100];
|
||||
itoa(c->noff, amt, 10);
|
||||
uart_puts(amt);
|
||||
}
|
||||
panic("pop_off");
|
||||
}
|
||||
c->noff -= 1;
|
||||
if (c->noff == 0 && c->intena)
|
||||
intr_on();
|
||||
}
|
||||
|
|
|
@ -1,22 +1,51 @@
|
|||
#ifndef KERNEL_SPINLOCK_H
|
||||
#define KERNEL_SPINLOCK_H
|
||||
#ifndef KERNEL_Spinlock_H
|
||||
#define KERNEL_Spinlock_H
|
||||
|
||||
#include <proc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t v; // 0 = unlocked, 1 = locked
|
||||
Cpu *cpu;
|
||||
} spinlock_t;
|
||||
/** Mutual exclusion spin lock */
|
||||
struct Spinlock {
|
||||
u32 locked; // Is the lock held?
|
||||
|
||||
uint32_t push_off(void);
|
||||
uint32_t pop_off(void);
|
||||
// NOTE: Perhaps feature gate this?
|
||||
|
||||
void spinlock_init(spinlock_t *l);
|
||||
bool spin_trylock(spinlock_t *l);
|
||||
void spin_unlock(spinlock_t *l);
|
||||
bool spin_is_holding(spinlock_t *l);
|
||||
void spin_lock(spinlock_t *l);
|
||||
// For debugging:
|
||||
char *name; // Name of lock.
|
||||
struct Cpu *cpu; // The cpu holding the lock.
|
||||
};
|
||||
|
||||
#endif // KERNEL_SPINLOCK_H
|
||||
/**
|
||||
* Acquire the lock.
|
||||
* Loops (spins) until the lock is acquired.
|
||||
* Panics if the lock is already held by this cpu.
|
||||
*/
|
||||
void acquire(struct Spinlock *);
|
||||
|
||||
/**
|
||||
* Check whether this cpu is holding the lock.
|
||||
* Interrupts must be off.
|
||||
*/
|
||||
int holding(struct Spinlock *);
|
||||
|
||||
/**
|
||||
* Initialize Spinlock
|
||||
*/
|
||||
void initlock(struct Spinlock *, char *);
|
||||
|
||||
/**
|
||||
* Release the lock.
|
||||
* Panics if the lock is not held.
|
||||
*/
|
||||
void release(struct Spinlock *);
|
||||
|
||||
/**
|
||||
* @brief push_off/pop_off are like intr_off()/intr_on() except that they are
|
||||
* matched: it takes two pop_off()s to undo two push_off()s. Also, if
|
||||
* interrupts are initially off, then push_off, pop_off leaves them off.
|
||||
*/
|
||||
void push_off(void);
|
||||
|
||||
/** @copydoc pop_off */
|
||||
void pop_off(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,4 +8,4 @@ typedef __builtin_va_list va_list;
|
|||
#define va_end(ap) __builtin_va_end(ap)
|
||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||
|
||||
#endif // _STDARG_H
|
||||
#endif
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef _STDBOOL_H
|
||||
#define _STDBOOL_H
|
||||
|
||||
/*TODO*/
|
||||
typedef char bool;
|
||||
enum { false = 0, true = 1 };
|
||||
|
||||
#endif // _STDBOOL_H
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef STDDEF_H
|
||||
#define STDDEF_H
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#ifndef size_t
|
||||
#define size_t uint64_t
|
||||
#endif
|
||||
|
||||
#endif // STDDEF_H
|
|
@ -1,42 +1,16 @@
|
|||
#ifndef STDINT_H
|
||||
#define STDINT_H
|
||||
#pragma once
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long u64;
|
||||
|
||||
typedef char i8;
|
||||
typedef short i16;
|
||||
typedef int i32;
|
||||
typedef long i64;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long uint64_t;
|
||||
typedef uint64_t size_t;
|
||||
|
||||
typedef char int8_t;
|
||||
typedef short int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long int64_t;
|
||||
|
||||
typedef uint64_t size_t;
|
||||
typedef uint64_t uintptr_t;
|
||||
|
||||
#define INT8_MIN (-128)
|
||||
#define INT16_MIN (-32767 - 1)
|
||||
#define INT32_MIN (-2147483647 - 1)
|
||||
#define INT64_MIN (-__INT64_C(9223372036854775807) - 1)
|
||||
|
||||
#define INT8_MAX (127)
|
||||
#define INT16_MAX (32767)
|
||||
#define INT32_MAX (2147483647)
|
||||
#define INT64_MAX (__INT64_C(9223372036854775807))
|
||||
|
||||
#define UINT8_MAX (255)
|
||||
#define UINT16_MAX (65535)
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#define UINT64_MAX (__UINT64_C(18446744073709551615))
|
||||
|
||||
#endif // STDINT_H
|
||||
// typedef u8 bool;
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
#include <mini-printf.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <uart.h>
|
||||
|
||||
/** Helper routine to put characters into our uart device */
|
||||
static int stdout_puts(char *s, int len, void *unused) {
|
||||
(void)unused;
|
||||
for (int i = 0; i < len; i++) uart_putc(s[i]);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Printf-like functionality for the kernel.
|
||||
*
|
||||
* %% - print '%',
|
||||
* %c - character,
|
||||
* %s - string,
|
||||
* %d, %u - decimal integer,
|
||||
* %x, %X - hex integer,
|
||||
*/
|
||||
int kprintf(const char *restrict fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = kvprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvprintf(const char *fmt, va_list ap) {
|
||||
int ret = mini_vpprintf(stdout_puts, NULL, fmt, ap);
|
||||
return ret;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef STDIO_H
|
||||
#define STDIO_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
int kprintf(const char *restrict format, ...);
|
||||
int kvprintf(const char *fmt, va_list ap);
|
||||
|
||||
// int fprintf(FILE *restrict stream, const char *restrict format, ...);
|
||||
// int dprintf(int fd, const char *restrict format, ...);
|
||||
// int sprintf(char *restrict str, const char *restrict format, ...);
|
||||
// int snprintf(char str[restrict.size], size_t size, const char *restrict format, ...);
|
||||
|
||||
// int vprintf(const char *restrict format, va_list ap);
|
||||
// int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap);
|
||||
// int vdprintf(int fd, const char *restrict format, va_list ap);
|
||||
// int vsprintf(char *restrict str, const char *restrict format, va_list ap);
|
||||
// int vsnprintf(char str[restrict.size], size_t size, const char *restrict format, va_list ap);
|
||||
|
||||
#endif // STDIO_H
|
|
@ -1,13 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
int abs(int a) {
|
||||
return a > 0 ? a : -a;
|
||||
}
|
||||
|
||||
long labs(long a) {
|
||||
return a > 0 ? a : -a;
|
||||
}
|
||||
|
||||
long long llabs(long long a) {
|
||||
return a > 0 ? a : -a;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef STDLIB_H
|
||||
#define STDLIB_H
|
||||
|
||||
#define EXIT_SUCCESS 0
|
||||
#define EXIT_FAILURE 1
|
||||
|
||||
int abs(int);
|
||||
long labs(long);
|
||||
long long llabs(long long);
|
||||
|
||||
#endif // STDLIB_H
|
|
@ -114,6 +114,18 @@ void *memset(void *dest, int c, size_t n) {
|
|||
return dest;
|
||||
}
|
||||
|
||||
// int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
// if (n != 0) {
|
||||
// const unsigned char *p1 = s1, *p2 = s2;
|
||||
//
|
||||
// do {
|
||||
// if (*p1++ != *p2++)
|
||||
// return (*--p1 - *--p2);
|
||||
// } while (--n != 0);
|
||||
// }
|
||||
// return (0);
|
||||
// }
|
||||
|
||||
char *itoa(int value, char *str, int base) {
|
||||
char *p = str;
|
||||
char *p1, *p2;
|
||||
|
@ -154,6 +166,39 @@ char *itoa(int value, char *str, int base) {
|
|||
return str;
|
||||
}
|
||||
|
||||
// void *memset(void *dst, int c, size_t length) {
|
||||
// u8 *ptr = (u8 *)dst;
|
||||
// const u8 value = (u8)c;
|
||||
//
|
||||
// while (length--) *(ptr++) = value;
|
||||
//
|
||||
// return dst;
|
||||
// }
|
||||
|
||||
// void *memcpy(void *dst, const void *src, size_t len) {
|
||||
// u8 *d = (u8 *)dst;
|
||||
// const u8 *s = (const u8 *)src;
|
||||
// for (size_t i = 0; i < len; i++) {
|
||||
// d[i] = s[i];
|
||||
// }
|
||||
// return dst;
|
||||
// }
|
||||
|
||||
// void *memmove(void *dst, const void *src, size_t len) {
|
||||
// u8 *d = (u8 *)dst;
|
||||
// const u8 *s = (const u8 *)src;
|
||||
// if (d < s) {
|
||||
// for (size_t i = 0; i < len; i++) {
|
||||
// d[i] = s[i];
|
||||
// }
|
||||
// } else if (d > s) {
|
||||
// for (size_t i = len; i > 0; i--) {
|
||||
// d[i - 1] = s[i - 1];
|
||||
// }
|
||||
// }
|
||||
// return dst;
|
||||
// }
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t len) {
|
||||
const u8 *a = (const u8 *)s1;
|
||||
const u8 *b = (const u8 *)s2;
|
||||
|
@ -178,20 +223,3 @@ size_t strnlen(const char *s, size_t maxlen) {
|
|||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int strncmp(const char *p, const char *q, u32 n) {
|
||||
while (n > 0 && *p && *p == *q) n--, p++, q++;
|
||||
if (n == 0)
|
||||
return 0;
|
||||
return (u8)*p - (u8)*q;
|
||||
}
|
||||
|
||||
char *strncpy(char *s, const char *t, int n) {
|
||||
char *os;
|
||||
|
||||
os = s;
|
||||
while (n-- > 0 && (*s++ = *t++) != 0) {
|
||||
}
|
||||
while (n-- > 0) *s++ = 0;
|
||||
return os;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define KERNEL_STRING_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// void *memcpy(void *s1, const void *s2, size_t n);
|
||||
// void *memmove(void *s1, const void *s2, size_t n);
|
||||
|
@ -31,17 +30,16 @@ size_t strlen(const char *s);
|
|||
/** Return length of string `s`, up to a max of `maxlen` bytes */
|
||||
size_t strnlen(const char *s, size_t maxlen);
|
||||
|
||||
int strncmp(const char *p, const char *q, u32 n);
|
||||
|
||||
char *strncpy(char *s, const char *t, int n);
|
||||
|
||||
// TODO: These:
|
||||
/*
|
||||
int strcmp(const char *s1, const char *s2);
|
||||
int strncmp(const char *s1, const char *s2, size_t n);
|
||||
|
||||
char *strcpy(char *dst, const char *src);
|
||||
char *strncpy(char *dst, const char *src, size_t n);
|
||||
|
||||
char *strchr(const char *s, int c);
|
||||
char *strrchr(const char *s, int c);
|
||||
*/
|
||||
|
||||
#endif // KERNEL_STRING_H
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* QEMU memory maps a UART device here. */
|
||||
#define UART_BASE ((volatile char *)0x10000000)
|
||||
|
||||
void uart_putc(char c) {
|
||||
*UART_BASE = c;
|
||||
void uart_putc(char c) { *UART_BASE = c; }
|
||||
|
||||
void uart_puts(const char *s) {
|
||||
while (*s) uart_putc(*s++);
|
||||
}
|
||||
|
|
|
@ -4,4 +4,7 @@
|
|||
/** Send a single character to the UART device */
|
||||
void uart_putc(char c);
|
||||
|
||||
#endif // UART_KERNEL_H
|
||||
/** Send a **NULL TERMINATED** string to the UART device */
|
||||
void uart_puts(const char *s);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
/*
|
||||
* Give hints to the compiler for branch prediction optimization.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 2))
|
||||
#define likely(c) (__builtin_expect(!!(c), 1))
|
||||
#define unlikely(c) (__builtin_expect(!!(c), 0))
|
||||
#else
|
||||
#define likely(c) (c)
|
||||
#define unlikely(c) (c)
|
||||
#endif
|
||||
|
||||
/* Round up to nearest power of two */
|
||||
static inline uint32_t next_power_of_two(uint32_t v) {
|
||||
/* See: https://graphics.stanford.edu/%7Eseander/bithacks.html#RoundUpPowerOf2 */
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return ++v;
|
||||
}
|
||||
|
||||
#endif // UTIL_H
|
22
kern/proc.h
22
kern/proc.h
|
@ -1,7 +1,5 @@
|
|||
#ifndef PROC_H
|
||||
#define PROC_H
|
||||
|
||||
#include <config.h>
|
||||
#include <spinlock.h>
|
||||
#include <riscv.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -15,7 +13,7 @@ typedef enum {
|
|||
} ProcessState;
|
||||
|
||||
/** Saved registers for kernel context switches. */
|
||||
typedef struct Context {
|
||||
struct Context {
|
||||
uint64_t ra;
|
||||
uint64_t sp;
|
||||
|
||||
|
@ -32,18 +30,18 @@ typedef struct Context {
|
|||
uint64_t s9;
|
||||
uint64_t s10;
|
||||
uint64_t s11;
|
||||
} Context;
|
||||
};
|
||||
|
||||
/** Per-CPU state. */
|
||||
typedef struct cpu_t {
|
||||
struct Cpu {
|
||||
struct Process *proc; // The process running on this cpu, or null.
|
||||
struct Context context; // swtch() here to enter scheduler().
|
||||
int noff; // Depth of push_off() nesting.
|
||||
int intena; // Were interrupts enabled before push_off()?
|
||||
} Cpu;
|
||||
};
|
||||
|
||||
/** Saved registers for kernel context switches. */
|
||||
typedef struct TrapFrame_t {
|
||||
typedef struct {
|
||||
/* 0 */ uint64_t kernel_satp; // kernel page table
|
||||
/* 8 */ uint64_t kernel_sp; // top of process's kernel stack
|
||||
/* 16 */ uint64_t kernel_trap; // usertrap()
|
||||
|
@ -80,13 +78,11 @@ typedef struct TrapFrame_t {
|
|||
/* 264 */ uint64_t t4;
|
||||
/* 272 */ uint64_t t5;
|
||||
/* 280 */ uint64_t t6;
|
||||
} TrapFrame;
|
||||
} TrapFrame_t;
|
||||
|
||||
Cpu *mycpu(void);
|
||||
struct Cpu *mycpu(void);
|
||||
|
||||
extern Cpu cpus[NCPU];
|
||||
extern struct Cpu cpus[NCPU];
|
||||
|
||||
/** Per-process state */
|
||||
struct Proc {};
|
||||
|
||||
#endif // PROC_H
|
||||
|
|
121
kern/slab.h
121
kern/slab.h
|
@ -1,121 +0,0 @@
|
|||
#ifndef SLAB_H
|
||||
#define SLAB_H
|
||||
|
||||
/*
|
||||
* To understand this code, some prerequisite knowledge on memory and allocators are
|
||||
* required. You should probably know what a free-list is, and maybe how to implement a bump allocator.
|
||||
*
|
||||
* See James Shackleford's excellent presentation on the Linux slab allocator:
|
||||
* https://www.youtube.com/watch?v=pFi-JKgoX-I
|
||||
*
|
||||
* In the Linux source tree, the slub implementation resides in:
|
||||
* mm/slub.c
|
||||
*
|
||||
* To see the slab caches on a linux system:
|
||||
* $ sudo cat /proc/slabinfo
|
||||
* In order of columns:
|
||||
* name, active obj, total n obj, obj size, obj per slab, pages per slab
|
||||
* For more info about how to decode this, see:
|
||||
* $ man 5 slabinfo
|
||||
*
|
||||
* The way kernel memory allocation works in modern unixes is essentially outlined by:
|
||||
* kmalloc() -> slub/slab/slob -> binary-buddy
|
||||
*
|
||||
* Where kmalloc redirects the requests to one of its appropriately sized slab caches,
|
||||
* which in turn checks for an available cache, and if not found, allocates a new one
|
||||
* using the binary-buddy allocator, which only allocates fixed size objects (usually pages)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define KERN_TOP_ADDR
|
||||
#define USER_TOP_ADDR
|
||||
|
||||
#define POISON_FREE 0x6b
|
||||
#define POISON_END 0x6a
|
||||
#define POISON_IN_USE 0x5a
|
||||
|
||||
#define RED_INACTIVE 0xbb
|
||||
#define RED_ACTIVE 0xcc
|
||||
|
||||
/* Canonical addresses are addresses that point to unmapped memory (neither user nor kernel space) */
|
||||
#define IS_CANONICAL_ADDRESS(ptr) (ptr < KERN_TOP_ADDR && ptr > USER_TOP_ADDR)
|
||||
|
||||
/* 'bin size', 'order' */
|
||||
#define SIZE_TO_KMALLOC_CACHE_INDEX(size) (0)
|
||||
struct kmem_cache *kmalloc_caches[10];
|
||||
|
||||
/* GetFreePages_t: The type used for flags in various allocation related functions */
|
||||
typedef uint32_t gfp_t;
|
||||
|
||||
/* Kmalloc manages an internal array of slab caches, sizes 8 bytes to 2^13 bytes */
|
||||
void *kzalloc(size_t size); // Same but zeroes memory
|
||||
void *kmalloc(size_t size) {
|
||||
/* If the order (size) is too large to fit inside one of the slab caches, go directly to frame (page, buddy)
|
||||
* allocator */
|
||||
struct kmem_cache *suitable_cache = kmalloc_caches[SIZE_TO_KMALLOC_CACHE_INDEX(size)];
|
||||
/* Do operations on kmem cache */
|
||||
(void)suitable_cache;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For big allocations, not physically contiguous */
|
||||
void *vmalloc(size_t size);
|
||||
|
||||
// SLAB_HWCACHE_ALIGN
|
||||
// SLAB_CACHE_DMA
|
||||
// SLAB_PANIC
|
||||
|
||||
/* This struct exists only conceptually, as the poison is variable in length */
|
||||
/* The struct within each slab */
|
||||
struct kmem_free_obj {
|
||||
/* FreePointer, pointer to the next free pointer in the slab, if null then full, essentially a linked list */
|
||||
/* Poison, inserted to see if someone reads or writes to a free area, checked by comparison, these values are known
|
||||
*/
|
||||
/* Pad, to keep things aligned*/
|
||||
};
|
||||
|
||||
/* This struct exists only conceptually */
|
||||
struct kmem_allocated_obj {
|
||||
char payload[128]; /* Sized for demonstration */
|
||||
char red_zone[16]; /* Sized for demonstration */
|
||||
};
|
||||
|
||||
/* Per cpu slab cache, to avoid worrying about locking */
|
||||
struct kmem_cache_cpu {
|
||||
/* FreeList, points to the _first free object_, which will be equal to the Page pointer if the page is empty */
|
||||
/* Page, the page allocated by buddy */
|
||||
/* Page_amt, there may be multiple pages */
|
||||
};
|
||||
|
||||
/* Essentially a list head for pages */
|
||||
struct kmem_page {
|
||||
/* Page */
|
||||
/* FirstFree */
|
||||
/* Slabsize? */
|
||||
/* Next */
|
||||
/* Prev? */
|
||||
};
|
||||
|
||||
/* Global (as in cross CPU) pointers to pages in various states */
|
||||
/* When kmem_cache_cpu->page gets full, it gets swapped into the full linked list */
|
||||
/* Operations on this struct requires locking */
|
||||
struct kmem_cache_node {
|
||||
/* Partial, linked list of kmem_page, moved from full once something inside a full page is free'd */
|
||||
/* Full, linked list of kmem_page */
|
||||
};
|
||||
|
||||
struct kmem_cache {
|
||||
const char *name;
|
||||
struct kmem_cache_cpu *cpu_slab;
|
||||
struct kmem_cache_node *node;
|
||||
};
|
||||
|
||||
// KMEM_CACHE macro
|
||||
// kmem_cache_create(name, size, alignment, flags, constructor)
|
||||
// kmem_cache_destroy(*kmem_cache)
|
||||
// kmem_cache_alloc(*kmem_cache, flags (GFP_KERNEL|GFP_ATOMIC|GFP_ZERO))
|
||||
// kmem_cache_free(*kmem_cache, *obj) <- Optionally checks redzone
|
||||
|
||||
#endif // SLAB_H
|
|
@ -1,13 +1,14 @@
|
|||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY( _entry ) /* See: entry.S */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 128M
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/*
|
||||
* ensure that entry.S / _entry is at 0x80000000,
|
||||
* where qemu's -kernel jumps.
|
||||
*/
|
||||
. = 0x80000000;
|
||||
|
||||
/*
|
||||
* This section contains the code. This is, the machine language instructions
|
||||
* that will be executed by the processor. In here we will find symbols
|
||||
|
@ -34,7 +35,7 @@ SECTIONS
|
|||
|
||||
/* Define symbol etext to be the current location. */
|
||||
PROVIDE(etext = .);
|
||||
} > RAM :text
|
||||
} :text
|
||||
|
||||
/*
|
||||
* This contains any data that is marked as read only.
|
||||
|
@ -46,7 +47,7 @@ SECTIONS
|
|||
*(.srodata*) /* do not need to distinguish this from .rodata */
|
||||
. = ALIGN(16);
|
||||
*(.rodata*)
|
||||
} > RAM
|
||||
}
|
||||
|
||||
/*
|
||||
* This section contains initialized global and static variables.
|
||||
|
@ -57,7 +58,7 @@ SECTIONS
|
|||
*(.sdata*) /* do not need to distinguish this from .data */
|
||||
. = ALIGN(16);
|
||||
*(.data*)
|
||||
} > RAM
|
||||
}
|
||||
|
||||
/*
|
||||
* Contains all uninitialized global and static var iables. These are usually
|
||||
|
@ -70,12 +71,10 @@ SECTIONS
|
|||
*(.sbss*) /* do not need to distinguish this from .bss */
|
||||
. = ALIGN(16);
|
||||
*(.bss*)
|
||||
} > RAM
|
||||
}
|
||||
|
||||
/* Define symbol end as current location, note that this is not aligned, see vm.c */
|
||||
PROVIDE(kernel_end = .);
|
||||
PROVIDE(__heap_start = ALIGN(32));
|
||||
PROVIDE(__heap_end = ORIGIN(RAM) + LENGTH(RAM));
|
||||
}
|
||||
|
||||
PHDRS {
|
|
@ -1,26 +0,0 @@
|
|||
The Minimal snprintf() implementation
|
||||
|
||||
Copyright (c) 2013 Michal Ludvig <michal@logix.cz>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the auhor nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,173 +0,0 @@
|
|||
Monocypher as a whole is dual-licensed. Choose whichever licence you
|
||||
want from the two licences listed below.
|
||||
|
||||
The first licence is a regular 2-clause BSD licence. The second licence
|
||||
is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
to the public domain. The BSD licence serves as a fallback option.
|
||||
|
||||
See the individual files for specific information about who contributed
|
||||
to what file during which years. See below for special notes.
|
||||
|
||||
Licence 1 (2-clause BSD)
|
||||
------------------------
|
||||
|
||||
Copyright (c) 2017-2023, Loup Vaillant
|
||||
Copyright (c) 2017-2019, Michael Savage
|
||||
Copyright (c) 2017-2023, Fabio Scotoni
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Licence 2 (CC-0)
|
||||
----------------
|
||||
|
||||
> CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
> LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
> ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
> INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
> REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
> PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
> THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
> HEREUNDER.
|
||||
|
||||
### Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work
|
||||
of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without
|
||||
fear of later claims of infringement build upon, modify, incorporate in
|
||||
other works, reuse and redistribute as freely as possible in any form
|
||||
whatsoever and for any purposes, including without limitation commercial
|
||||
purposes. These owners may contribute to the Commons to promote the
|
||||
ideal of a free culture and the further production of creative, cultural
|
||||
and scientific works, or to gain reputation or greater distribution for
|
||||
their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or
|
||||
she is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under
|
||||
its terms, with knowledge of his or her Copyright and Related Rights in
|
||||
the Work and the meaning and intended legal effect of CC0 on those
|
||||
rights.
|
||||
|
||||
1. **Copyright and Related Rights.** A Work made available under CC0 may
|
||||
be protected by copyright and related or neighboring rights
|
||||
("Copyright and Related Rights"). Copyright and Related Rights
|
||||
include, but are not limited to, the following:
|
||||
|
||||
- the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
- moral rights retained by the original author(s) and/or
|
||||
performer(s); publicity and privacy rights pertaining to a person's
|
||||
image or likeness depicted in a Work;
|
||||
- rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
- rights protecting the extraction, dissemination, use and reuse of
|
||||
data in a Work;
|
||||
- database rights (such as those arising under Directive 96/9/EC of
|
||||
the European Parliament and of the Council of 11 March 1996 on the
|
||||
legal protection of databases, and under any national
|
||||
implementation thereof, including any amended or successor version
|
||||
of such directive); and
|
||||
- other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. **Waiver.** To the greatest extent permitted by, but not in
|
||||
contravention of, applicable law, Affirmer hereby overtly, fully,
|
||||
permanently, irrevocably and unconditionally waives, abandons, and
|
||||
surrenders all of Affirmer's Copyright and Related Rights and
|
||||
associated claims and causes of action, whether now known or unknown
|
||||
(including existing as well as future claims and causes of action),
|
||||
in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"Waiver"). Affirmer makes the Waiver for the benefit of each member
|
||||
of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal
|
||||
or equitable action to disrupt the quiet enjoyment of the Work by the
|
||||
public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. **Public License Fallback.** Should any part of the Waiver for any
|
||||
reason be judged legally invalid or ineffective under applicable law,
|
||||
then the Waiver shall be preserved to the maximum extent permitted
|
||||
taking into account Affirmer's express Statement of Purpose. In
|
||||
addition, to the extent the Waiver is so judged Affirmer hereby
|
||||
grants to each affected person a royalty-free, non transferable, non
|
||||
sublicensable, non exclusive, irrevocable and unconditional license
|
||||
to exercise Affirmer's Copyright and Related Rights in the Work (i)
|
||||
in all territories worldwide, (ii) for the maximum duration provided
|
||||
by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and
|
||||
(iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "License"). The
|
||||
License shall be deemed effective as of the date CC0 was applied by
|
||||
Affirmer to the Work. Should any part of the License for any reason
|
||||
be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the
|
||||
remainder of the License, and in such case Affirmer hereby affirms
|
||||
that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any
|
||||
associated claims and causes of action with respect to the Work, in
|
||||
either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. **Limitations and Disclaimers.**
|
||||
|
||||
- No trademark or patent rights held by Affirmer are waived,
|
||||
abandoned, surrendered, licensed or otherwise affected by this
|
||||
document.
|
||||
- Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy,
|
||||
or the present or absence of errors, whether or not discoverable,
|
||||
all to the greatest extent permissible under applicable law.
|
||||
- Affirmer disclaims responsibility for clearing rights of other
|
||||
persons that may apply to the Work or any use thereof, including
|
||||
without limitation any person's Copyright and Related Rights in the
|
||||
Work. Further, Affirmer disclaims responsibility for obtaining any
|
||||
necessary consents, permissions or other rights required for any
|
||||
use of the Work.
|
||||
- Affirmer understands and acknowledges that Creative Commons is not
|
||||
a party to this document and has no duty or obligation with respect
|
||||
to this CC0 or use of the Work.
|
||||
|
||||
Special notes
|
||||
-------------
|
||||
|
||||
The files in `tests/externals/` were placed in the public domain by
|
||||
their respective authors. See the `AUTHORS.md` files in each directory.
|
|
@ -1,193 +0,0 @@
|
|||
musl as a whole is licensed under the following standard MIT license:
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Copyright © 2005-2020 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Authors/contributors include:
|
||||
|
||||
A. Wilcox
|
||||
Ada Worcester
|
||||
Alex Dowad
|
||||
Alex Suykov
|
||||
Alexander Monakov
|
||||
Andre McCurdy
|
||||
Andrew Kelley
|
||||
Anthony G. Basile
|
||||
Aric Belsito
|
||||
Arvid Picciani
|
||||
Bartosz Brachaczek
|
||||
Benjamin Peterson
|
||||
Bobby Bingham
|
||||
Boris Brezillon
|
||||
Brent Cook
|
||||
Chris Spiegel
|
||||
Clément Vasseur
|
||||
Daniel Micay
|
||||
Daniel Sabogal
|
||||
Daurnimator
|
||||
David Carlier
|
||||
David Edelsohn
|
||||
Denys Vlasenko
|
||||
Dmitry Ivanov
|
||||
Dmitry V. Levin
|
||||
Drew DeVault
|
||||
Emil Renner Berthing
|
||||
Fangrui Song
|
||||
Felix Fietkau
|
||||
Felix Janda
|
||||
Gianluca Anzolin
|
||||
Hauke Mehrtens
|
||||
He X
|
||||
Hiltjo Posthuma
|
||||
Isaac Dunham
|
||||
Jaydeep Patil
|
||||
Jens Gustedt
|
||||
Jeremy Huntwork
|
||||
Jo-Philipp Wich
|
||||
Joakim Sindholt
|
||||
John Spencer
|
||||
Julien Ramseier
|
||||
Justin Cormack
|
||||
Kaarle Ritvanen
|
||||
Khem Raj
|
||||
Kylie McClain
|
||||
Leah Neukirchen
|
||||
Luca Barbato
|
||||
Luka Perkov
|
||||
Lynn Ochs
|
||||
M Farkas-Dyck (Strake)
|
||||
Mahesh Bodapati
|
||||
Markus Wichmann
|
||||
Masanori Ogino
|
||||
Michael Clark
|
||||
Michael Forney
|
||||
Mikhail Kremnyov
|
||||
Natanael Copa
|
||||
Nicholas J. Kain
|
||||
orc
|
||||
Pascal Cuoq
|
||||
Patrick Oppenlander
|
||||
Petr Hosek
|
||||
Petr Skocik
|
||||
Pierre Carrier
|
||||
Reini Urban
|
||||
Rich Felker
|
||||
Richard Pennington
|
||||
Ryan Fairfax
|
||||
Samuel Holland
|
||||
Segev Finer
|
||||
Shiz
|
||||
sin
|
||||
Solar Designer
|
||||
Stefan Kristiansson
|
||||
Stefan O'Rear
|
||||
Szabolcs Nagy
|
||||
Timo Teräs
|
||||
Trutz Behn
|
||||
Will Dietz
|
||||
William Haddon
|
||||
William Pitcock
|
||||
|
||||
Portions of this software are derived from third-party works licensed
|
||||
under terms compatible with the above MIT license:
|
||||
|
||||
The TRE regular expression implementation (src/regex/reg* and
|
||||
src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
|
||||
under a 2-clause BSD license (license text in the source files). The
|
||||
included version has been heavily modified by Rich Felker in 2012, in
|
||||
the interests of size, simplicity, and namespace cleanliness.
|
||||
|
||||
Much of the math library code (src/math/* and src/complex/*) is
|
||||
Copyright © 1993,2004 Sun Microsystems or
|
||||
Copyright © 2003-2011 David Schultz or
|
||||
Copyright © 2003-2009 Steven G. Kargl or
|
||||
Copyright © 2003-2009 Bruce D. Evans or
|
||||
Copyright © 2008 Stephen L. Moshier or
|
||||
Copyright © 2017-2018 Arm Limited
|
||||
and labelled as such in comments in the individual source files. All
|
||||
have been licensed under extremely permissive terms.
|
||||
|
||||
The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008
|
||||
The Android Open Source Project and is licensed under a two-clause BSD
|
||||
license. It was taken from Bionic libc, used on Android.
|
||||
|
||||
The AArch64 memcpy and memset code (src/string/aarch64/*) are
|
||||
Copyright © 1999-2019, Arm Limited.
|
||||
|
||||
The implementation of DES for crypt (src/crypt/crypt_des.c) is
|
||||
Copyright © 1994 David Burren. It is licensed under a BSD license.
|
||||
|
||||
The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was
|
||||
originally written by Solar Designer and placed into the public
|
||||
domain. The code also comes with a fallback permissive license for use
|
||||
in jurisdictions that may not recognize the public domain.
|
||||
|
||||
The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
|
||||
Lynn Ochs and is licensed under an MIT-style license.
|
||||
|
||||
The x86_64 port was written by Nicholas J. Kain and is licensed under
|
||||
the standard MIT terms.
|
||||
|
||||
The mips and microblaze ports were originally written by Richard
|
||||
Pennington for use in the ellcc project. The original code was adapted
|
||||
by Rich Felker for build system and code conventions during upstream
|
||||
integration. It is licensed under the standard MIT terms.
|
||||
|
||||
The mips64 port was contributed by Imagination Technologies and is
|
||||
licensed under the standard MIT terms.
|
||||
|
||||
The powerpc port was also originally written by Richard Pennington,
|
||||
and later supplemented and integrated by John Spencer. It is licensed
|
||||
under the standard MIT terms.
|
||||
|
||||
All other files which have no copyright comments are original works
|
||||
produced specifically for use as part of this library, written either
|
||||
by Rich Felker, the main author of the library, or by one or more
|
||||
contibutors listed above. Details on authorship of individual files
|
||||
can be found in the git version control history of the project. The
|
||||
omission of copyright and license comments in each file is in the
|
||||
interest of source tree size.
|
||||
|
||||
In addition, permission is hereby granted for all public header files
|
||||
(include/* and arch/*/bits/*) and crt files intended to be linked into
|
||||
applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit
|
||||
the copyright notice and permission notice otherwise required by the
|
||||
license, and to use these files without any requirement of
|
||||
attribution. These files include substantial contributions from:
|
||||
|
||||
Bobby Bingham
|
||||
John Spencer
|
||||
Nicholas J. Kain
|
||||
Rich Felker
|
||||
Richard Pennington
|
||||
Stefan Kristiansson
|
||||
Szabolcs Nagy
|
||||
|
||||
all of whom have explicitly granted such permission.
|
||||
|
||||
This file previously contained text expressing a belief that most of
|
||||
the files covered by the above exception were sufficiently trivial not
|
||||
to be subject to copyright, resulting in confusion over whether it
|
||||
negated the permissions granted in the license. In the spirit of
|
||||
permissive licensing, and of not having licensing issues being an
|
||||
obstacle to adoption, that text has been removed.
|
|
@ -1,23 +0,0 @@
|
|||
The xv6 software is:
|
||||
|
||||
Copyright (c) 2006-2024 Frans Kaashoek, Robert Morris, Russ Cox,
|
||||
Massachusetts Institute of Technology
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,15 +1,10 @@
|
|||
#include <assert.h>
|
||||
#include <banner.h>
|
||||
#include <buddy.h>
|
||||
#include <config.h>
|
||||
#include <ispinlock.h>
|
||||
#include <kalloc.h>
|
||||
#include <memory.h>
|
||||
#include <panic.h>
|
||||
#include <proc.h>
|
||||
#include <riscv.h>
|
||||
#include <spinlock.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <uart.h>
|
||||
|
||||
/**
|
||||
|
@ -41,26 +36,31 @@ void start() {
|
|||
|
||||
if (id == 0) {
|
||||
/* Here we will do a bunch of initialization steps */
|
||||
memory_sweep(heap_start, heap_end);
|
||||
buddy_init(heap_start, heap_end);
|
||||
kalloc_init();
|
||||
uart_puts("Hello Neptune!\n");
|
||||
spinlock_init(&sl);
|
||||
for (int i = 0; i < banner_len; i++) uart_putc(banner[i]);
|
||||
__sync_synchronize();
|
||||
hold = 0;
|
||||
} else {
|
||||
while (hold);
|
||||
}
|
||||
|
||||
// spin_lock(&sl);
|
||||
//
|
||||
// uart_puts("Hart number: ");
|
||||
// uart_putc(id + '0');
|
||||
// uart_putc('\n');
|
||||
//
|
||||
// spin_unlock(&sl);
|
||||
|
||||
if (id == 0) {
|
||||
spin_lock(&sl);
|
||||
kprintf("Core count: %d\n", max_hart);
|
||||
|
||||
if (max_hart == NCPU)
|
||||
kprintf("All cores up!\n");
|
||||
else
|
||||
PANIC("Some cores seem to have been enumerated incorrectly!\n");
|
||||
|
||||
kprintf("To exit qemu, press CTRL+a followed by x\n");
|
||||
uart_puts("Core count: ");
|
||||
uart_putc(max_hart + '0');
|
||||
uart_putc('\n');
|
||||
if (max_hart == NCPU) {
|
||||
uart_puts("All cores up!");
|
||||
uart_putc('\n');
|
||||
}
|
||||
spin_unlock(&sl);
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue