Skip to content

Commit

Permalink
Merge pull request s-matyukevich#223 from szediwy/master
Browse files Browse the repository at this point in the history
Solved lesson 01 exercise 3 for Raspberry Pi 4B
  • Loading branch information
s-matyukevich authored Jan 12, 2021
2 parents a26ead7 + f601eb8 commit 87a0323
Show file tree
Hide file tree
Showing 16 changed files with 381 additions and 0 deletions.
34 changes: 34 additions & 0 deletions exercises/lesson01/3/szediwy/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
ARMGNU ?= aarch64-linux-gnu

COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only
ASMOPS = -Iinclude

BUILD_DIR = build
SRC_DIR = src

.PHONY: clean

all : kernel8.img

clean :
rm -rf $(BUILD_DIR) *.img
@echo "clean: [SUCCESS]"

$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c
mkdir -p $(@D)
$(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@

$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S
$(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@

C_FILES = $(wildcard $(SRC_DIR)/*.c)
ASM_FILES = $(wildcard $(SRC_DIR)/*.S)
OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o)
OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o)

DEP_FILES = $(OBJ_FILES:%.o=%.d)
-include $(DEP_FILES)

kernel8.img: $(SRC_DIR)/linker.ld $(OBJ_FILES)
$(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES)
$(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img
1 change: 1 addition & 0 deletions exercises/lesson01/3/szediwy/build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker run --rm -v %cd%:/app -w /app smatyukevich/raspberry-pi-os-builder make %1
3 changes: 3 additions & 0 deletions exercises/lesson01/3/szediwy/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

docker run --rm -v $(pwd):/app -w /app smatyukevich/raspberry-pi-os-builder make $1
9 changes: 9 additions & 0 deletions exercises/lesson01/3/szediwy/include/mini_uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef _MINI_UART_H
#define _MINI_UART_H

void uart_init ( void );
char uart_recv ( void );
void uart_send ( char c );
void uart_send_string(char* str);

#endif /*_MINI_UART_H */
19 changes: 19 additions & 0 deletions exercises/lesson01/3/szediwy/include/mm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef _MM_H
#define _MM_H

#define PAGE_SHIFT 12
#define TABLE_SHIFT 9
#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT)

#define PAGE_SIZE (1 << PAGE_SHIFT)
#define SECTION_SIZE (1 << SECTION_SHIFT)

#define LOW_MEMORY (2 * SECTION_SIZE)

#ifndef __ASSEMBLER__

void memzero(unsigned long src, unsigned long n);

#endif

#endif /*_MM_H */
10 changes: 10 additions & 0 deletions exercises/lesson01/3/szediwy/include/peripherals/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef _P_BASE_H
#define _P_BASE_H

// #define PBASE 0x3F000000
// So a peripheral described in this document as being at legacy address 0x7Enn_nnnn is available in the 35-bit address
// space at 0x4_7Enn_nnnn, and visible to the ARM at 0x0_FEnn_nnnn if Low Peripheral mode is enabled.
// 0x7E000000 (legacy) -> 0x4_7E00_0000 (35-bit) -> 0x0_FE00_0000 (low peripheral)
#define PBASE 0xFE000000

#endif /*_P_BASE_H */
20 changes: 20 additions & 0 deletions exercises/lesson01/3/szediwy/include/peripherals/gpio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef _P_GPIO_H
#define _P_GPIO_H

#include "peripherals/base.h"

#define GPFSEL1 (PBASE+0x00200004)
// #define GPSET0 (PBASE+0x0020001C)
// #define GPCLR0 (PBASE+0x00200028)
// #define GPPUD (PBASE+0x00200094)
// #define GPPUDCLK0 (PBASE+0x00200098)
#define GPIO_PUP_PDN_CNTRL_REG0 (PBASE+0x002000E4)
#define UART0_DR (PBASE+0x00201000)
#define UART0_FR (PBASE+0x00201018)
#define UART0_IBRD (PBASE+0x00201024)
#define UART0_FBRD (PBASE+0x00201028)
#define UART0_LCRH (PBASE+0x0020102C)
#define UART0_CR (PBASE+0x00201030)
#define UART0_IMSC (PBASE+0x00201038)

#endif /*_P_GPIO_H */
19 changes: 19 additions & 0 deletions exercises/lesson01/3/szediwy/include/peripherals/mini_uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef _P_MINI_UART_H
#define _P_MINI_UART_H

#include "peripherals/base.h"

#define AUX_ENABLES (PBASE+0x00215004)
#define AUX_MU_IO_REG (PBASE+0x00215040)
#define AUX_MU_IER_REG (PBASE+0x00215044)
#define AUX_MU_IIR_REG (PBASE+0x00215048)
#define AUX_MU_LCR_REG (PBASE+0x0021504C)
#define AUX_MU_MCR_REG (PBASE+0x00215050)
#define AUX_MU_LSR_REG (PBASE+0x00215054)
#define AUX_MU_MSR_REG (PBASE+0x00215058)
#define AUX_MU_SCRATCH (PBASE+0x0021505C)
#define AUX_MU_CNTL_REG (PBASE+0x00215060)
#define AUX_MU_STAT_REG (PBASE+0x00215064)
#define AUX_MU_BAUD_REG (PBASE+0x00215068)

#endif /*_P_MINI_UART_H */
8 changes: 8 additions & 0 deletions exercises/lesson01/3/szediwy/include/utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef _BOOT_H
#define _BOOT_H

extern void delay ( unsigned long);
extern void put32 ( unsigned long, unsigned int );
extern unsigned int get32 ( unsigned long );

#endif /*_BOOT_H */
127 changes: 127 additions & 0 deletions exercises/lesson01/3/szediwy/src/boot.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#include "mm.h"

.section ".text.boot"

.globl _start
_start:
mrs x0, mpidr_el1
and x0, x0, #0x3
cbz x0, init_bss
/* If processor id is not 0 then pending lock processor
* (wait for `sev` instruction)
*/
wfe
b master

proc_hang:
b proc_hang

init_bss:
adr x0, bss_begin
adr x1, bss_end
sub x1, x1, x0
bl memzero

sev

/***********************************************************************/
/* Enable the other cores
link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm64/booting.rst?h=v5.3#n255
The boot loader is expected to enter the kernel on each CPU in the
following manner:
- The primary CPU must jump directly to the first instruction of the
kernel image. The device tree blob passed by this CPU must contain
an 'enable-method' property for each cpu node. The supported
enable-methods are described below.
It is expected that the bootloader will generate these device tree
properties and insert them into the blob prior to kernel entry.
- CPUs with a "spin-table" enable-method must have a 'cpu-release-addr'
property in their cpu node. This property identifies a
naturally-aligned 64-bit zero-initalised memory location.
These CPUs should spin outside of the kernel in a reserved area of
memory (communicated to the kernel by a /memreserve/ region in the
device tree) polling their cpu-release-addr location, which must be
contained in the reserved region. A wfe instruction may be inserted
to reduce the overhead of the busy-loop and a sev will be issued by
the primary CPU. When a read of the location pointed to by the
cpu-release-addr returns a non-zero value, the CPU must jump to this
value. The value will be written as a single 64-bit little-endian
value, so CPUs must convert the read value to their native endianness
before jumping to it.
- CPUs with a "psci" enable method should remain outside of
the kernel (i.e. outside of the regions of memory described to the
kernel in the memory node, or in a reserved area of memory described
to the kernel by a /memreserve/ region in the device tree). The
kernel will issue CPU_ON calls as described in ARM document number ARM
DEN 0022A ("Power State Coordination Interface System Software on ARM
processors") to bring CPUs into the kernel.
The device tree should contain a 'psci' node, as described in
Documentation/devicetree/bindings/arm/psci.yaml.
- Secondary CPU general-purpose register settings
x0 = 0 (reserved for future use)
x1 = 0 (reserved for future use)
x2 = 0 (reserved for future use)
x3 = 0 (reserved for future use)
*/

/* cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <0>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x000000d8>;
};
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <1>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x000000e0>;
};
cpu2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <2>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x000000e8>;
};
cpu3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <3>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x000000f0>;
}; */
/****************************************************/
mov x0, #0
adr x0, master

mov x1, #0xe0
str x0, [x1]
mov x1, #0xe8
str x0, [x1]
mov x1, #0xf0
str x0, [x1]

master:
mrs x0, mpidr_el1
and x0, x0, #0x3

mov x1, #SECTION_SIZE
mul x1, x1, x0
add x1, x1, #LOW_MEMORY
mov sp, x1

bl kernel_main
b proc_hang
4 changes: 4 additions & 0 deletions exercises/lesson01/3/szediwy/src/config.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
arm_64bit=1
enable_uart=1
uart_2ndstage=1
disable_commandline_tags=1
28 changes: 28 additions & 0 deletions exercises/lesson01/3/szediwy/src/kernel.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "mini_uart.h"

void kernel_main(unsigned long processor_index)
{
static unsigned int current_processor_index = 0;

if (processor_index == 0) {
uart_init();
}

while (processor_index != current_processor_index)
;

uart_send_string("Hello from processor ");
uart_send(processor_index + '0');
uart_send_string("!\r\n");

current_processor_index++;

if (processor_index == 0) {
// if current_processor_index == 4 then all processors send message
while (current_processor_index != 4)
;
for (;;) {
uart_send(uart_recv());
}
}
}
11 changes: 11 additions & 0 deletions exercises/lesson01/3/szediwy/src/linker.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SECTIONS
{
.text.boot : { *(.text.boot) }
.text : { *(.text) }
.rodata : { *(.rodata) }
.data : { *(.data) }
. = ALIGN(0x8);
bss_begin = .;
.bss : { *(.bss*) }
bss_end = .;
}
67 changes: 67 additions & 0 deletions exercises/lesson01/3/szediwy/src/mini_uart.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "utils.h"
#include "peripherals/mini_uart.h"
#include "peripherals/gpio.h"

void uart_send(char c)
{
while (get32(UART0_FR) & (1 << 5))
{
}
put32(UART0_DR, c);
}

char uart_recv(void)
{
while (get32(UART0_FR) & (1 << 4))
{
}
return (get32(UART0_DR) & 0xFF);
}

void uart_send_string(char *str)
{
for (int i = 0; str[i] != '\0'; i++)
{
uart_send((char)str[i]);
}
}

void uart_init(void)
{

unsigned int selector;

selector = get32(GPFSEL1);
selector &= ~(7 << 12); // clean gpio14
selector |= 4 << 12; // set alt5 for gpio14
selector &= ~(7 << 15); // clean gpio15
selector |= 4 << 15; // set alt5 for gpio15
put32(GPFSEL1, selector);

unsigned int pullRegister;
pullRegister = get32(GPIO_PUP_PDN_CNTRL_REG0);
pullRegister &= ~(3 << 30);
pullRegister &= ~(3 << 28);
put32(GPIO_PUP_PDN_CNTRL_REG0, pullRegister);

//first disable uart
put32(UART0_CR, 0);
put32(UART0_IMSC, 0);

//from ../adkaster/src/uart.c
// Assume 48MHz UART Reference Clock (Standard)
// Calculate UART clock divider per datasheet
// BAUDDIV = (FUARTCLK/(16 Baud rate))
// Note: We get 6 bits of fraction for the baud div
// 48000000/(16 * 115200) = 3000000/115200 = 26.0416666...
// Integer part = 26 :)
// From http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0183g/I54603.html
// we want floor(0.04166666.. * 64 + 0.5) = 3
put32(UART0_IBRD, 26);
put32(UART0_FBRD, 3);

//little endian: 0111|0000 => 8 bits and enable fifos
put32(UART0_LCRH, 7 << 4);
//little endian: 0011|0000|0001 => enable: rx tx uart
put32(UART0_CR, (1 << 9) | (1 << 8) | (1 << 0));
}
6 changes: 6 additions & 0 deletions exercises/lesson01/3/szediwy/src/mm.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.globl memzero
memzero:
str xzr, [x0], #8
subs x1, x1, #8
b.gt memzero
ret
15 changes: 15 additions & 0 deletions exercises/lesson01/3/szediwy/src/utils.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.globl put32
put32:
str w1,[x0]
ret

.globl get32
get32:
ldr w0,[x0]
ret

.globl delay
delay:
subs x0, x0, #1
bne delay
ret

0 comments on commit 87a0323

Please sign in to comment.