Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Lab4/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.associations": {
"utils.h": "c"
}
}
35 changes: 35 additions & 0 deletions Lab4/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
CC = aarch64-linux-gnu-gcc
AS = aarch64-linux-gnu-as
CFLAGS = -Iinclude -Iperipherals -fno-stack-protector -g
ASFLAGS =
BUILD_DIR = build

# Define peripherals source files
PERIPHERALS_SRC_C = $(wildcard peripherals/*.c)
PERIPHERALS_SRC_S = $(wildcard peripherals/*.S)
PERIPHERALS_OBJS = $(PERIPHERALS_SRC_C:%.c=$(BUILD_DIR)/%.o) $(PERIPHERALS_SRC_S:%.S=$(BUILD_DIR)/%.o)

# Target for peripherals
$(BUILD_DIR)/peripherals/%.o: peripherals/%.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/peripherals/%.o: peripherals/%.S
@mkdir -p $(@D)
$(AS) $(ASFLAGS) $< -o $@

# all: peripherals bootloader kernel
all: peripherals kernel bootloader

peripherals: $(PERIPHERALS_OBJS)

kernel:
$(MAKE) -C kernel BUILD_DIR=../$(BUILD_DIR)

bootloader:
$(MAKE) -C bootloader BUILD_DIR=../$(BUILD_DIR)

clean:
rm -rf $(BUILD_DIR)

.PHONY: all peripherals kernel bootloader clean
47 changes: 47 additions & 0 deletions Lab4/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
The cpio archive format collects any number of files, directories, and
other file system objects (symbolic links, device nodes, etc.) into a
single stream of bytes.


CPIO New ASCII Format

The "new" ASCII format uses 8-byte hexadecimal fields for all numbers
and separates device numbers into separate fields for major and minor
numbers.

struct cpio_newc_header {
char c_magic[6];
char c_ino[8];
char c_mode[8];
char c_uid[8];
char c_gid[8];
char c_nlink[8];
char c_mtime[8];
char c_filesize[8];
char c_devmajor[8];
char c_devminor[8];
char c_rdevmajor[8];
char c_rdevminor[8];
char c_namesize[8];
char c_check[8];
};

Except as specified below, the fields here match those specified for
the new binary format above.

magic The string "070701".

check This field is always set to zero by writers and ignored by
readers. See the next section for more details.

The pathname is followed by NUL bytes so that the total size of the
fixed header plus pathname is a multiple of four. Likewise, the file
data is padded to a multiple of four bytes. Note that this format sup-
ports only 4 gigabyte files (unlike the older ASCII format, which sup-
ports 8 gigabyte files).

In this format, hardlinked files are handled by setting the filesize to
zero for each entry except the first one that appears in the archive.

create a cpio archive:
find . | cpio -o -H newc > ../initramfs.cpio
Binary file added Lab4/a.out
Binary file not shown.
Binary file added Lab4/archive/bcm2710-rpi-3-b-plus.dtb
Binary file not shown.
Binary file added Lab4/archive/initramfs.cpio
Binary file not shown.
2 changes: 2 additions & 0 deletions Lab4/archive/rootfs/dir1/sub_dir1/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This is test!
Newline.
Binary file added Lab4/bcm2710-rpi-3-b-plus.dtb
Binary file not shown.
Binary file added Lab4/bootloader.zip
Binary file not shown.
33 changes: 33 additions & 0 deletions Lab4/bootloader/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
CC = aarch64-linux-gnu-gcc
AS = aarch64-linux-gnu-as
LD = aarch64-linux-gnu-ld
OBJCOPY = aarch64-linux-gnu-objcopy
CFLAGS = -I../include -I../peripherals -fno-stack-protector -g
ASFLAGS =

# Adjust these paths as necessary
SRC_C = $(wildcard *.c)
SRC_S = $(wildcard *.S)
OBJS = $(SRC_C:%.c=$(BUILD_DIR)/bootloader/%.o) $(SRC_S:%.S=$(BUILD_DIR)/bootloader/%.o)

# Include peripherals objects
PERIPHERALS_OBJS = $(wildcard $(BUILD_DIR)/peripherals/*.o)
LINKER_SCRIPT = linker.ld
BOOTLOADER_ELF = $(BUILD_DIR)/bootloader/bootloader.elf
BOOTLOADER_IMG = $(BUILD_DIR)/bootloader/bootloader.img

all: $(OBJS) bootloader

$(BUILD_DIR)/bootloader/%.o: %.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/bootloader/%.o: %.S
@mkdir -p $(@D)
$(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@

bootloader: $(OBJS) $(PERIPHERALS_OBJS)
$(LD) -T $(LINKER_SCRIPT) -o $(BOOTLOADER_ELF) $^
$(OBJCOPY) -O binary $(BOOTLOADER_ELF) $(BOOTLOADER_IMG)

.PHONY: all bootloader
69 changes: 69 additions & 0 deletions Lab4/bootloader/boot.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "../peripherals/mm.h"

.section ".text.boot"

.global _start

_start:
// The initial state of the registers x0, x1, x2, and x3 upon startup holds specific information
// passed by the firmware/bootloader.
// x0: The 64-bit machine model number (from the Device Tree Blob, or DTB). This is an identifier
// for the hardware model the software is running on, which can be used to adjust behaviors or
// operations for different hardware variants if necessary.
mov x10, x0
// x1: The physical address of the Device Tree Blob (DTB) in memory. The DTB is a binary
// representation of the device tree, which describes the hardware components of the system in a
// tree-like structure. This includes information about the processor, memory, peripherals, and
// other hardware components. The operating system or bootloader can parse the DTB to dynamically
// discover the hardware configuration of the system.
mov x11, x1
// x2: Reserved or unused in the standard Raspberry Pi boot process. Its value may not be defined
// or may be specific to certain configurations or future use. It's often safe to assume this register
// does not hold information critical to the initial boot process unless specified by new documentation
// or specific boot configurations.
mov x12, x2
// x3: Reserved or unused, similar to x2. Its purpose is dependent on the booting firmware or specific
// use cases and is generally not used in the standard boot process for Raspberry Pi.
mov x13, x3

// Relocate the boatloader(0x80000) to another location(0x60000) to avoid overlapping with kernel.
self_relocate:
ldr x2, =0x60000
adr x0, __bootloader_start
adr x1, __bootloader_end
sub x1, x1, x0

relocate:
ldr x3, [x0], #8
str x3, [x2], #8
subs x1, x1, #8
b.gt relocate


// Initialize the bss section.
clear_bss:
// Initialize stack pointer.
mov sp, #LOW_MEMORY
adr x0, __bss_start
adr x1, __bss_end
sub x1, x1, x0

// Iterate through the bss section and initialize it with zeros.
memzero:
// Stores the value from the zero register(xzr) to the memory location pointed to
// by x0. After storing the bytes, increment x0 by 8 bytes, since it's a 64-bit
// architecture.
str xzr, [x0], #8

// x1 contains the size of bss that needs to be zeroed out. subs also updates
// the condition flags based on the result.
subs x1, x1, #8

// It's a conditional branch that jumps back to memzero label if the condition
// flags indicate that the result of the previous "subs" was greater than zero.
b.gt memzero
bl bootloader_main - 0x20000

// This step shouldn't be reached, define it just in case.
proc_hang:
b proc_hang
52 changes: 52 additions & 0 deletions Lab4/bootloader/bootloader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "../peripherals/mini_uart.h"
#include "bootloader.h"
#include "../peripherals/utils.h"

void bootloader_main(unsigned long address) {
// Location to load the kernel.
char* kernel = (char *)0x80000;

// Store the size of the kernel image.
unsigned int size = 0;

// Setup mini uart.
uart_init();
uart_send_string("\r\nBooting...\r\n");
uart_send_string("Kernel image size: ");
uart_send_string("0x");
size = get_kernel_size();
uart_send_uint(size);
uart_send_string(" bytes\r\n");

while (size--) {
// uart_send_string("Loading Kernel\r\n");
*kernel++ = uart_recv();
}

uart_send_string("Kernel loaded.\r\n");

// Give uart enough time to send "Kernel loaded." message.
delay(5000);

asm volatile(
"mov x0, x10;"
"mov x1, x11;"
"mov x2, x12;"
"mov x3, x13;"
"mov x30, 0x80000;"
"ret;"
);

}

unsigned int get_kernel_size(void) {
unsigned int size = 0;

// The uart transfers 4 bytes at a time, while the uart_recv() reads 1 byte every time.
for (int i = 0; i < 4; i++) {
char c = uart_recv();
size |= ((unsigned int)c & 0xFF) << (i * 8);
}

return size;
}
7 changes: 7 additions & 0 deletions Lab4/bootloader/bootloader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef _BOOTLOADER_H_
#define _BOOTLOADER_H_

void bootloader_main(unsigned long address);
unsigned int get_kernel_size(void);

#endif
24 changes: 24 additions & 0 deletions Lab4/bootloader/linker.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
SECTIONS
{
. = 0x80000;
__bootloader_start = .;
PROVIDE(_code = .);
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
# Here I used 16 because some machines support 4-byte, 8-byte, and 16-byte. The bootloader should
# be as fast as possible, so here I used 16. The kernel, on the other hand, uses 8-byte for maximum
# compatibility and performance.
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
. = ALIGN(8);
__bootloader_end = .;

/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
Binary file added Lab4/firmware/bootcode.bin
Binary file not shown.
3 changes: 3 additions & 0 deletions Lab4/firmware/config.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kernel=bootloader.img
arm_64bit=1
initramfs initramfs.cpio 0x30000000
Binary file added Lab4/firmware/fixup.dat
Binary file not shown.
Binary file added Lab4/firmware/start.elf
Binary file not shown.
Binary file added Lab4/initramfs.cpio
Binary file not shown.
33 changes: 33 additions & 0 deletions Lab4/kernel/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
CC = aarch64-linux-gnu-gcc
AS = aarch64-linux-gnu-as
LD = aarch64-linux-gnu-ld
OBJCOPY = aarch64-linux-gnu-objcopy
CFLAGS = -I../include -I../peripherals -fno-stack-protector -g -O0
ASFLAGS =

# Adjust these paths as necessary
SRC_C = $(wildcard *.c)
SRC_S = $(wildcard *.S)
OBJS = $(SRC_C:%.c=$(BUILD_DIR)/kernel/%.o) $(SRC_S:%.S=$(BUILD_DIR)/kernel/%.o)

# Include peripherals objects
PERIPHERALS_OBJS = $(wildcard $(BUILD_DIR)/peripherals/*.o)
LINKER_SCRIPT = linker.ld
KERNEL8_ELF = $(BUILD_DIR)/kernel/kernel8.elf
KERNEL8_IMG = $(BUILD_DIR)/kernel/kernel8.img

all: $(OBJS) kernel

$(BUILD_DIR)/kernel/%.o: %.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/%.o: %.S
@mkdir -p $(@D)
$(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@

kernel: $(OBJS) $(PERIPHERALS_OBJS)
$(LD) -T $(LINKER_SCRIPT) -o $(KERNEL8_ELF) $^
$(OBJCOPY) -O binary $(KERNEL8_ELF) $(KERNEL8_IMG)

.PHONY: all kernel
Loading