From d79436a1170e4d5ffde77416313587f320c8e590 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Mon, 18 Nov 2024 15:56:37 +0100 Subject: usr: Bootstrap the initramfs for the kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a sample `foo` program which already calls the `write_and_block` system call which is yet to be implemented by this kernel. Moreover, the same CPIO format is used for the initramfs as with Linux, so we can pass it with QEMU without worries. Signed-off-by: Miquel Sabaté Solà --- .gitignore | 2 ++ Makefile | 49 +++++++++++++++++++++++++++++++++++++++---------- README.md | 5 +++-- usr/src/foo.S | 13 +++++++++++++ 4 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 usr/src/foo.S diff --git a/.gitignore b/.gitignore index f1ccbff..d87610d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ kernel/fbos.ld /fbos .cache +usr/bin/* +usr/initramfs.cpio # You can generate it with Bear: `$ bear -- make`. compile_commands.json diff --git a/Makefile b/Makefile index df82342..6799281 100644 --- a/Makefile +++ b/Makefile @@ -18,15 +18,19 @@ endif # no `-mcpu`, no `-mtune`, no funny business. CC = $(CROSS_COMPILE)gcc$(CC_SUFFIX) +AS = $(CROSS_COMPILE)as$(CC_SUFFIX) LD = $(CROSS_COMPILE)ld QEMU ?= qemu-system-riscv64 ISA ?= rv64imafdc_zicntr_zicsr_zifencei_zihpm_zca_zcd_zba_zbb -CCFLAGS = -march=$(ISA) -Iinclude/ -mabi=lp64d +ASFLAGS = -march=$(ISA) -mabi=lp64d +CCFLAGS = $(ASFLAGS) -Iinclude/ CCFLAGS += -Werror -Wpedantic -Wall -Wextra -Wcast-align -Wcast-qual -Winit-self \ -Wmissing-include-dirs -Wredundant-decls -Wshadow -Wsign-conversion \ - -Wswitch-default -Wundef -Wunreachable-code -Wmissing-noreturn -LDFLAGS = -Iinclude/ -static -nostdlib -melf64lriscv -z noexecstack + -Wswitch-default -Wundef -Wunreachable-code -Wmissing-noreturn \ + -nostdinc -nostdlib -std=gnu17 +LDFLAGS = -Iinclude/ -static -melf64lriscv -z noexecstack +USRFLAGS = -static -melf64lriscv ## # Optional parameters for QEMU and gdb. @@ -42,26 +46,29 @@ GDB_EXTRA_FLAGS ?= DEBUG = ifeq ($(strip $(DEBUG)),) CCFLAGS += -O3 + QEMU_FLAGS += -nographic else CCFLAGS += -g QEMU_FLAGS += -s -S endif ## -# Paths. +# Paths SRC = $(wildcard kernel/head.S kernel/*.c) OBJ = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SRC))) LINKER = kernel/fbos.ld KRNL = fbos +USR = usr/bin/foo +INIT = usr/initramfs.cpio LDFLAGS += -T $(LINKER) ## -# Targets +# Kernel .PHONY: all -all: clean $(KRNL) +all: clean $(KRNL) usr .PHONY: $(KRNL) $(KRNL): $(OBJ) $(LINKER).S @@ -78,12 +85,34 @@ $(KRNL): $(OBJ) $(LINKER).S $(E) " CC " $(*F) $(Q) $(CC) $(CCFLAGS) -c $< -o $@ +## +# User space + +.PHONY: usr +usr: $(USR) + $(E) " CPIO " $(INIT) + $(Q) find usr/bin/ -type f -executable | cpio -o --quiet -H newc > $(INIT) + +usr/src/%.o: usr/src/%.S + $(E) " AS " $(basename $@) + $(Q) $(AS) $(ASFLAGS) -c $< -o $@ + +usr/bin/%: usr/src/%.o + $(E) " LD " $@ + $(Q) $(LD) $(USRFLAGS) $< -o $@ + +# HACK: do not remove object files from usr/src/. +.SECONDARY: + +## +# Hacking + .PHONY: qemu -qemu: $(KRNL) +qemu: $(KRNL) usr ifeq ($(strip $(QEMU_BIOS)),) - $(Q) $(QEMU) $(QEMU_FLAGS) -machine virt -kernel $(KRNL) -nographic + $(Q) $(QEMU) $(QEMU_FLAGS) -machine virt -kernel $(KRNL) -initrd $(INIT) else - $(Q) $(QEMU) $(QEMU_FLAGS) -machine virt -bios $(QEMU_BIOS) -kernel $(KRNL) -nographic + $(Q) $(QEMU) $(QEMU_FLAGS) -machine virt -bios $(QEMU_BIOS) -kernel $(KRNL) -initrd $(INIT) endif .PHONY: gdb @@ -92,7 +121,7 @@ gdb: .PHONY: clean clean: - $(Q) rm -f $(OBJ) $(KRNL) $(LINKER) + $(Q) rm -f $(OBJ) $(KRNL) $(LINKER) $(USR) usr/src/*.o $(INIT) .PHONY: lint lint: diff --git a/README.md b/README.md index 5833b55..8ce947f 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ are unaware of each other and it's up to the kernel to schedule them by using the timer interrupts as given by openSBI (`fizz` on % 3 seconds, `buzz` on % 5 seconds, and `fizzbuzz` on % 15 seconds). -This kernel provides just one system call, `write`, which allows any program to -pass the string to be written into the serial port. +This kernel provides just one system call, `write_and_block`, which allows any +program to pass the string to be written into the serial port and wait for the +kernel to re-schedule it. ## Build diff --git a/usr/src/foo.S b/usr/src/foo.S new file mode 100644 index 0000000..57e82a1 --- /dev/null +++ b/usr/src/foo.S @@ -0,0 +1,13 @@ +.global _start +.text + +_start: + li a0, 1 + la a1, foo + ecall +.Loop: + j .Loop + +.section .rodata +foo: + .string "foo\n" -- cgit v1.2.3