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
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ RUN apt-get update
# Install QEMU for emulation
RUN apt-get install -y \
qemu-system-arm \
gdb \
gdb-multiarch \
sudo

# Install the AArch64 cross-compiler toolchain
Expand All @@ -30,6 +30,11 @@ RUN apt-get install -y \
# make gcc alia to aarch64-linux-gnu-gcc
RUN echo "alias gcc='aarch64-linux-gnu-gcc'" >> ~/.bashrc

# install python dependicies
RUN apt install -y python3-pip

RUN pip install pyserial

# clean up package caches
RUN rm -rf /var/lib/apt/lists/*

Expand Down
48 changes: 14 additions & 34 deletions lab_2/README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
Tutorial 03 - UART1, Auxilary mini UART
=======================================

It is time for the famous Hello World example. We're going to write on the UART1 first, as it's easier to program
as it has a fixed clocked frequency.

NOTE: qemu does not redirect UART1 to terminal by default, only UART0, so you have to use `-serial null -serial stdio`.

Gpio.h
------

We have a new header file. This defines the base MMIO address, and the GPIO controller's addresses. This file
going to be very popular, as many devices need it.

Uart.h, uart.c
--------------

A very minimal implementation.

`uart_init()` initializes the device and maps it to the GPIO ports.

`uart_send(c)` sends a character over the serial line.

`uart_getc()` receives a character. The carrige return character (13) will be converted into a newline character (10).

`uart_puts(s)` prints out a string. On newline, a carrige return character will also be sent (13 + 10).

Main
----

First, we have to call the uart initialization code. Then, it'll return "Hello World!". If you've purchased an USB
serial cable, you should see it on minicom's screen. After that every character typed in minicom will be
echoed back. If you haven't turned off local echo, that means you'll see every pressed key twice.

1. python UART transfer data loss
- AUX_MU_LSR_REG bit 1: This bit is set if there was a receiver overrun. That is:
one or more characters arrived whilst the receive
FIFO was full. The newly arrived charters have been
discarded. This bit is cleared each time this register is
read. To do a non-destructive read of this overrun bit
use the Mini Uart Extra Status register.
[reference: P15](https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf)

2. init UART register to avoid garbage pending
3. link loader can arrange the .text section freely
- why align
4. wze is for halting CPU that is not id 0
5.
9 changes: 8 additions & 1 deletion lab_2/bootloader/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ clean:
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

run:
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial pty -display none -d in_asm
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb

run_asm:
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial pty -display none -dtb bcm2710-rpi-3-b-plus.dtb -d in_asm


run_stdio:
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -initrd initramfs.cpio -serial stdio -display none -dtb bcm2710-rpi-3-b-plus.dtb

debug:
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -s -S
Binary file added lab_2/bootloader/bcm2710-rpi-3-b-plus.dtb
Binary file not shown.
74 changes: 74 additions & 0 deletions lab_2/bootloader/device_tree.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "include/device_tree.h"
#include "include/uart.h"
// #include <stdio.h>
// #include <stdlib.h>

device_tree_header myHeader;

void header_parser(uintptr_t dtb_address){
uint32_t* start;
//uint32_t* dtb = mock_load_file();
uint32_t* dtb = dtb_address;
start = dtb;
// __builtin_bswap32() is a GCC built-in function to convert to the system's endianness.(RPi uses little-endian)
myHeader.magic = __builtin_bswap32(*dtb++);
if ((myHeader.magic - 0xd00dfeed) != 0) {
uart_puts("DTB magic number doesn't match!\r\n");
return 1;
}
myHeader.totalsize = __builtin_bswap32(*dtb++);
myHeader.off_dt_struct = __builtin_bswap32(*dtb++);
myHeader.off_dt_strings = __builtin_bswap32(*dtb++);
myHeader.off_mem_rsvmap = __builtin_bswap32(*dtb++);
myHeader.version = __builtin_bswap32(*dtb++);
myHeader.last_comp_version = __builtin_bswap32(*dtb++);
myHeader.boot_cpuid_phys = __builtin_bswap32(*dtb++);
myHeader.size_dt_strings = __builtin_bswap32(*dtb++);
myHeader.size_dt_struct = __builtin_bswap32(*dtb++);

// jump to structure
uint32_t* structure_ptr = (uint32_t *)(start + myHeader.off_dt_struct);
while(1){
uint32_t token = __builtin_bswap32(*structure_ptr++);
if(token == FDT_BEGIN_NODE){
uart_puts("Start\n");
}
}

//The node’s name as a null-terminated string



}

// unsigned long* mock_load_file() {
// FILE *file = fopen("bcm2710-rpi-3-b-plus.dtb", "rb");
// if (!file) {
// perror("Failed to open file");
// return 1;
// }

// // Get the size of the file
// fseek(file, 0, SEEK_END);
// long fileSize = ftell(file);
// rewind(file);

// // Allocate memory to hold the entire file
// unsigned char *buffer = (unsigned char *)malloc(fileSize);
// if (!buffer) {
// perror("Failed to allocate memory");
// fclose(file);
// return 1;
// }

// // Read the entire file into the buffer
// size_t bytesRead = fread(buffer, 1, fileSize, file);
// if (bytesRead != fileSize) {
// perror("Failed to read file");
// free(buffer);
// fclose(file);
// return 1;
// }

// return (unsigned long*)buffer;
// }
34 changes: 34 additions & 0 deletions lab_2/bootloader/include/device_tree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "stdint.h"


typedef struct fdt_header {
// 0xd00dfeed (big-endian)
uint32_t magic;
uint32_t totalsize;
// offsets of each block from start
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;

uint32_t version;
uint32_t last_comp_version;
// physical ID of the system’s boot CPU
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
} device_tree_header;

#define ALIGN_MEMORY_BLOCK 8

/* All tokens shall be aligned on a 32-bit boundary */
#define ALIGN_STRUCT_BLOCK 4

/* tokens used for structure block */
#define FDT_BEGIN_NODE 0x00000001
#define FDT_END_NODE 0x00000002
#define FDT_PROP 0x00000003
#define FDT_NOP 0x00000004
#define FDT_END 0x00000009


void header_parser();
9 changes: 9 additions & 0 deletions lab_2/bootloader/include/stdint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

typedef unsigned int uint16_t;

typedef unsigned long uint32_t;

typedef unsigned long long uint64_t;
typedef unsigned long uintptr_t;
typedef float float32;
typedef double float64;
Binary file added lab_2/bootloader/initramfs.cpio
Binary file not shown.
44 changes: 36 additions & 8 deletions lab_2/bootloader/kernel_uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
import os
import os.path
import sys
import time

port = '/dev/pts/3'

print("please enter the serial port: ", end="")
port = input()
port = "/dev/"+port
# port = '/dev/pts/1'
s = serial.Serial(port, baudrate=115200)

def read_line(s):
Expand All @@ -18,24 +23,47 @@ def read_line(s):
return received_string

size = os.stat("../shell/shell_kernel.img").st_size
print(size)
# size = os.stat("./kernel8.img").st_size

size_bytes = size.to_bytes(4,"little")
print(f"size from python: {hex(size)}")
s.write(size_bytes)

time.sleep(1)
# get response of correctness of bytes size sent
received_size = read_line(s)
print(received_size)
while s.in_waiting > 0:
received_content = read_line(s)
print(received_content)

with open("../shell/shell_kernel.img", "rb") as f:
sent_size = 0 # Initialize size counter

with open("../shell/shell_kernel.img","rb") as f:
s.write(f.read())
byte = f.read(1) # Read the first byte
while byte:
s.write(byte) # Send the byte over serial
# s.flush() # Flush the output buffer
sent_size += 1 # Increment size counter
byte = f.read(1) # Read the next byte


assert sent_size == size
print("kernel sent successfully.")

# get response of whether kernel is loaded successfully or not
received_content = read_line(s)
print(received_content)
time.sleep(1)
while(True):
while s.in_waiting > 0:
received_content = read_line(s)
print(received_content)
print("#", end=" ")
inp = input()
if(inp == ""):
continue
inp += "\n"
bytes_to_send = inp.encode('utf-8')
s.write(bytes_to_send)
print(received_content)
#while s.in_waiting > 0:
# received_content = read_line(s)
# print(received_content)
time.sleep(1)
17 changes: 14 additions & 3 deletions lab_2/bootloader/link.ld
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,24 @@
* DEALINGS IN THE SOFTWARE.
*
*/

SECTIONS
{
. = 0x60000;
PROVIDE(_head = .);
.text : { KEEP(*(.text.boot)) *(.text .text.*) }
.rodata : { *(.rodata .rodata.*) }
.relocate : {
KEEP(*(.text.relocate))
}
. = ALIGN(4096);

.imgLoader : {
KEEP(*(.text.load_img))
}
. = ALIGN(4096);
.text : {
KEEP(*(.text.boot))
*(.text)
}
. = ALIGN(4096);
PROVIDE(_data = .);
.data : { *(.data .data.*) }
.bss : {
Expand Down
19 changes: 9 additions & 10 deletions lab_2/bootloader/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include "include/uart.h"
#include "include/utils.h"
#include "include/mbox.h"
#include "include/stdint.h"
#include "include/device_tree.h"

void load_img(){
unsigned int size = 0;
Expand All @@ -35,27 +37,24 @@ void load_img(){
size_buffer[i] = uart_getc();
uart_puts("size-check correct\n");

uart_puts("Kernel size received: ");
uart_hex(size);
uart_puts("\n");

char *kernel = (char *) 0x80000;
while(size--) *kernel++ = uart_getc();

uart_puts("kernel-loaded\n");

asm volatile(
"mov x30, 0x80000;"
"ret;"
);
return;

}

void main(int argc, char* argv[]){
asm volatile(
"mov x10, x0"
);
void relocator(uintptr_t dtb_address){
uart_init();
// header_parser(dtb_address);
load_img();
asm volatile(
"mov x30, 0x80000;"
"mov x0, x10;"
"ret;"
);
}
9 changes: 9 additions & 0 deletions lab_2/bootloader/reader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
with open("./bcm2710-rpi-3-b-plus.dtb", "rb") as f:
data = f.read()
# Filter out the 0x00 bytes
filtered_data = bytes(b for b in data if b != 0x00)

# Print the filtered binary data
print(filtered_data)

#print(data)
Loading