icampbell
Posts: 3
Joined: Tue Nov 19, 2019 11:07 pm

Building my own RPi3 OS

Tue Nov 19, 2019 11:19 pm

Hello RPi forums!

I am attempting to follow bztsrc's online RPi bare metal guide (Located here: https://github.com/bztsrc/raspi3-tutorial) to create my own OS for the RPi3 and then port it to the RPi4! I have gotten pretty far. Currently my repo can be build and tested with qemu! Allowing me to test out the tiny shell I have made! But when I load up the kernel onto my SD card I get a blank screen that doesn't display anything onto my serial terminal. I have downloaded the kernel image from bztsrc's guide in Chapter 5 and tested it on my hardware setup and it worked properly. But using his UART guide I am still unable to properly create and setup UART to start my OS. I was hoping if someone could help me debug and take a look at my code to tell me where I have gone wrong. Part of my problem was that I started with a guide by jsandler (on github) and using this guide https://wiki.osdev.org/Raspberry_Pi_Bare_Bones on osdev. The combination of guides has not served me well. So the problem appears to be initializing the UART or properly compiling/linking the kernel. Which would seem strange because it works with qemu. Please if you have any ideas please let me know! Here is my repo:
https://github.com/icampbell-rit/ianos/tree/64bit

I really would appreciate any help. I am a hopeful embedded software engineer who is picking up RPi as a hobby! I will also gladly fill in anyone with additional details if necessary!

LdB
Posts: 1325
Joined: Wed Dec 07, 2016 2:29 pm

Re: Building my own RPi3 OS

Wed Nov 20, 2019 3:24 am

Your uart set speed tag message is wrong ... no idea where you got the extra parameter idea
try

Code: Select all

mbox[0] = 8*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETCLKRATE;
mbox[3] = 8;
mbox[4] = 8;
mbox[5] = 2;
mbox[6] = 4000000;
mbox[7] = MBOX_TAG_LAST;
mbox_call(MBOX_CH_PROP); 
I didn't test but you wont get you UART baud rate and I can imagine you may crash the VC out

You also have the old valvers mailbox code bug that never dies .. it will work until it randomly crashes.
You only have the VC4 to ARM status at offset 0x18 with no ARM to VC4 status at offset 0x38
You then read the 0x18 when deciding if the VC4 write mailbox is full before writing :-)

The mailbox interface is shown down the bottom
https://github.com/raspberrypi/firmware/wiki/Mailboxes
Channel 0 is VC4 to ARM status is 0x18 read is 0x0
Channel 1 is ARM to VC4 status is 0x38 write is 0x20

You need something like this definition

Code: Select all

#define MBOX_STATUS1     ((volatile unsigned int*)(VIDEOCORE_MBOX+0x38)) 
This line is wrong

Code: Select all

    do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
Given the above definition it then becomes

Code: Select all

    do{asm volatile("nop");}while(*MBOX_STATUS1 & MBOX_FULL);

Finally your current makefile looks like it set to cortex-a72 that is Pi4 only, you need cortex-a53 on a Pi3.

icampbell
Posts: 3
Joined: Tue Nov 19, 2019 11:07 pm

Re: Building my own RPi3 OS

Wed Nov 20, 2019 10:57 pm

LdB wrote:
Wed Nov 20, 2019 3:24 am
Your uart set speed tag message is wrong ... no idea where you got the extra parameter idea
try

Code: Select all

mbox[0] = 8*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETCLKRATE;
mbox[3] = 8;
mbox[4] = 8;
mbox[5] = 2;
mbox[6] = 4000000;
mbox[7] = MBOX_TAG_LAST;
mbox_call(MBOX_CH_PROP); 
...
So I did all the changes you mentioned here in this post! I am still getting nothing on powering the Pi on. The uart init message I got from this guide https://github.com/bztsrc/raspi3-tutori ... rt0/uart.c And I copied that pretty much word for word in those sections! I fixed the makefile issue which I knew about but forgot to push, and the other issue makes sense! But I still am not getting anything on the screen on putty when I load everything up. This guide I just linked has a kernel already built and I can use that properly. So in that case I am now wondering if I am not linking/making everything correctly? I feel like otherwise it must be something else in my uart_init part. The mbox array is still sized at 36 bytes (taken from guide). Is that accurate or would that mess things up? I wouldn't think it would, but I am not sure. Thank you so much for your first comment! I really appreciate the help! I am learning so much and any further help would be amazing!

LdB
Posts: 1325
Joined: Wed Dec 07, 2016 2:29 pm

Re: Building my own RPi3 OS

Thu Nov 21, 2019 3:07 am

I will have a crack at compiling your repo and see if I can see an issue.
All I will do first is dump a map file (if you aren't already doing it) and see what it is putting in the img file. That eliminates all those issues and we get down to code problems.
Update:
Okay I cant help that code wont even compile for me you obviously have warnings down at there lowest level.

Your personal standard library functions throw lots of errors and warnings
List2.h throws up never ending problems with its macros

I have no idea why you want to provide you own standard C libs when starting out.
You are compiling with the baremetal compiler the standard libraries work and at least and makes it easy for people to debug.
You want to save a few cycles some time down the track and write some fancy standard lib then knock yourself out

I tried deleting the common directory in both src and header commenting out memcpy and patching the includes back to
<stdlib.h> etc but your other code seems to rely on non C standard function headers. Things like bzero which looks like
it is something like a calloc or memset equivalent. Another one was "gets" you version has to many parameters.

Anyhow I gave up all too hard and I am not playing around with butchered C standard API functions.

icampbell
Posts: 3
Joined: Tue Nov 19, 2019 11:07 pm

Re: Building my own RPi3 OS

Thu Nov 21, 2019 9:14 pm

LdB wrote:
Thu Nov 21, 2019 3:07 am
I will have a crack at compiling your repo and see if I can see an issue.
All I will do first is dump a map file (if you aren't already doing it) and see what it is putting in the img file. That eliminates all those issues and we get down to code problems.
Update:
Okay I cant help that code wont even compile for me you obviously have warnings down at there lowest level.

Your personal standard library functions throw lots of errors and warnings
List2.h throws up never ending problems with its macros
...
Yeah I know its a total mess! I followed a different guide before switching to a new one. The old guide had lots of erroneous code and I attempted to salvage stuff from it. That was not a good decision. I totally get where you are coming from. I have never done this before and I didn't know what I was doing! I think you are right and the best option is to scrap what I have and focus on just getting the basics and uart working. Then once I can see a little output start re implementing my own functionality over that. Frankly that is what I should have done all along! This is a personal project so I am on no time constraint. I am sorry I led you into a C trap! I really do appreciate all your comments. And thank you for your help, it may not be easy to see but I have learned a lot from this project and this interaction! Thank you!

LdB
Posts: 1325
Joined: Wed Dec 07, 2016 2:29 pm

Re: Building my own RPi3 OS

Fri Nov 22, 2019 12:09 am

Can I also suggest you drop the arm to EL1 for your OS. The processor is designed with a basic philosophy
Image

If you look at the sheet the OS is really designed to sit at EL1. Specialist OS may do something different
but when you are starting out it is best to keep it as it was designed.

If it helps this is like a minimal setup on real hardware

Code: Select all

.globl _start
_start:
//"================================================================"
//  Set some valid stack pointer for EL0, EL1, EL2 for Core
//"================================================================"
        ldr        x0, =0x80000
	mov	sp, x0								/* EL2 stack set */
        sub         x0, x0, #0x10000                       
	msr	sp_el1, x0							/* EL1 stack set */
        sub         x0, x0, #0x10000
	msr	sp_el0, x0							/* EL0 stack set */

//"================================================================"
//  Initialize Generic Timers for Core
//"================================================================"
	mrs	x0, cnthctl_el2
	orr	x0, x0, #0x3						/* Enable EL1 access to timers */
	msr	cnthctl_el2, x0
	msr	cntvoff_el2, xzr
	
	mrs	x0, cntkctl_el1
	orr	x0, x0, #0x3						/* Enable EL0 access to timers */
	msr	cntkctl_el1, x0

//"================================================================"
//  Initilize MPID/MPIDR registers for Core
//"================================================================"
	mrs	x0, midr_el1
	mrs	x1, mpidr_el1
	msr	vpidr_el2, x0
	msr	vmpidr_el2, x1

//"================================================================"
//  Disable coprocessor traps for Core
//"================================================================"
	mov	x0, #0x33ff
	msr	cptr_el2, x0						// Disable coprocessor traps to EL2
	msr	hstr_el2, xzr						// Disable coprocessor traps to EL2
	mov	x0, #3 << 20
	msr	cpacr_el1, x0						// Enable FP/SIMD at EL1

//"================================================================"
//  Initialize HCR_EL2 so EL1 is 64 bits for Core
//"================================================================"
	mov	x0, #(1 << 31)						// 64bit EL1
	msr	hcr_el2, x0

//"================================================================"
//  Initialize SCTLR_EL1 for Core
//"================================================================"
    /*  RES1 bits (29,28,23,22,20,11) to 1
	 *  RES0 bits (31,30,27,21,17,13,10,6) +
	 *  UCI,EE,EOE,WXN,nTWE,nTWI,UCT,DZE,I,UMA,SED,ITD,
	 *  CP15BEN,SA0,SA,C,A,M to 0 */
	mov	x0, #0x0800
	movk	x0, #0x30d0, lsl #16
	orr    x0, x0, #(0x1 << 2)            // The C bit on (data cache). 
	orr    x0, x0, #(0x1 << 12)           // The I bit on (instruction cache)
	msr	sctlr_el1, x0

//"================================================================"
//  Return to the EL1_SP1 mode from EL2 for Core
//"================================================================"
	mov	x0, #0x3c5							// EL1_SP1 | D | A | I | F
	msr	spsr_el2, x0						// Set spsr_el2 with settings
	adr	x0, exit_el1						// Address to exit EL2
	msr	elr_el2, x0							// Set elevated return register
	eret									// Call elevated return
exit_el1:

//"================================================================"
//  Set vector table for EL1 for Core
//"================================================================"
    ldr x0, =YOURVectorTable						
    msr vbar_el1,x0

Return to “Bare metal, Assembly language”