xiGUAwanOU
Posts: 7
Joined: Sat Aug 09, 2014 8:28 pm

Questions about 0x8000, interrupts and memory structure

Tue Aug 26, 2014 1:51 pm

Hello there,

recently I'm working on my bare metal studies and get stucked at the memory structure of the bare metal programs. And now I'm focusing on the following 4 questions:


Question 1.

I've read some codes from dwelch67 and found there are many "mov sp, #0x8000" in the code, and the kernel.img itself will be loaded to 0x8000 on a running Pi. So should the memory layout in a running Pi like this below?

Code: Select all

========= top of the mem space

 NOT USED

--------- end of the bare metal program

BARE METAL
 PROGRAM

--------- 0x00008000

STACK SPACE
  GROWING
 DOWNWARDS

========= 0x00000000
Question 2.

As a result, the LDRs for the interrupt handling (is it called IVT?) at the beginning should also be loaded to 0x8000 with other codes in kernel.img? That means, RESET interrupts should make ARM jump to 0x8000, IRQ interrupts to 0x801C, etc.?


Question 3.

We should initialize each SP for different running modes. Is there any "common way" or conventions to do this? Or, which considerations we should take to make a proper memory structure?


Question 4.

I've been told that the memory space in RPi are shared between VC and ARM. There is a 512MB space for B+, and the ratio between the space for VC and ARM can be modified in config.txt. So I read the documents about config.txt and found there may be an option called gpu_mem to do this. By default the value of this option is 64MB. As a result, we could only use the lower (512 - 64) * 1024 * 1024 * 8 / 32 = 0x07000000 addresses in the total 0x08000000 addresses? However I've found "mov sp, #0x08000000" in some examples. So what am I missing here?


Many Thx!
xiguawanou

xiGUAwanOU
Posts: 7
Joined: Sat Aug 09, 2014 8:28 pm

Re: Questions about 0x8000, interrupts and memory structure

Tue Aug 26, 2014 2:45 pm

Found a mistake here:
As a result, we could only use the lower (512 - 64) * 1024 * 1024 * 8 / 32 = 0x07000000 addresses in the total 0x08000000 addresses?
One address points to data which is only 8 bits = 1 Byte long instead of 32 bits. So As a result, we can use the lower (512 - 64) * 1024 * 1024 = 0x1C000000 addresses in the total 0x20000000 addresses. Obviously is 0x08000000 in the range.

Sorry for the mistake =(

So Question 4 is answered, still waiting for the answer to Q1~Q3.
Last edited by xiGUAwanOU on Tue Aug 26, 2014 8:26 pm, edited 1 time in total.

User avatar
rpdom
Posts: 17029
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: Questions about 0x8000, interrupts and memory structure

Tue Aug 26, 2014 4:04 pm

The interrupt table always starts from 0x00000000 with a set of MOV PC,... type instructions, usually loading the PC from an address table immediately following the main table.

dwelch67
Posts: 966
Joined: Sat May 26, 2012 5:32 pm

Re: Questions about 0x8000, interrupts and memory structure

Tue Aug 26, 2014 4:14 pm

First off, this is bare metal so within the confines of what the hardware can do you are in control.

Many of my examples set the stack to 0x8000 so that 0x8000 down is the stack and 0x8000 up is the bare metal program.

So part of the reason I did this is that the primary use case as defined by the creators is for this board to run linux or whatever for kids and the linux distros by default use 0x8000, so that means the gpu booting arm at 0x8000 is the well used and tested use case. So I didnt have strong argument to change that. Then you get the added benefit of a little bit of memory for the stack and I dont have to try to hit the exact amount of memory in the chip for the arm or whatever.

Yes absolutely for this type of arm you need to set the various stack pointers for the different modes, and the "standard" way of doing this is somewhere in bootstrap you switch modes and set the stack pointer, I may or may not have anything like that in my examples but you see it done in other folks code.

as far as your other question about 0x08000000 if it is my code maybe that is a bug or would have to research where I got that number, or someone else may answer that...

David

dwelch67
Posts: 966
Joined: Sat May 26, 2012 5:32 pm

Re: Questions about 0x8000, interrupts and memory structure

Tue Aug 26, 2014 4:47 pm

the interrupt vector table or exception table is still at arm address 0x0000 so if you go with the approach of kernel.img loading at 0x8000, arm linux kernal style, then you have to build up the exception table somehow. If you use config.txt to place your binary at zero then you have to find a place for the stack pointer dont use 0x8000...you will probably collide with the stack

User avatar
AndrewS
Posts: 3625
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
Contact: Website

Re: Questions about 0x8000, interrupts and memory structure

Tue Aug 26, 2014 6:21 pm

dwelch67 wrote:If you use config.txt to place your binary at zero
The 'kernel_address' option in http://www.raspberrypi.org/documentatio ... fig-txt.md if you're wondering how to change it... ;)

xiGUAwanOU
Posts: 7
Joined: Sat Aug 09, 2014 8:28 pm

Re: Questions about 0x8000, interrupts and memory structure

Tue Aug 26, 2014 8:21 pm

Many thanks to you all for answering my questions!

So according to the answers, I've gained new understandings for my questions.

Question 1:

According to
dwelch67 wrote:Many of my examples set the stack to 0x8000 so that 0x8000 down is the stack and 0x8000 up is the bare metal program.
So I think my memory structure graph in Question 1 is correct.

Question 2:

According to
rpdom wrote:The interrupt table always starts from 0x00000000 with a set of MOV PC,... type instructions, usually loading the PC from an address table immediately following the main table.
and
dwelch67 wrote:The interrupt vector table or exception table is still at arm address 0x0000 so if you go with the approach of kernel.img loading at 0x8000, arm linux kernal style, then you have to build up the exception table somehow.
so my understanding about IVT is wrong. I'll give it a new try later.

Question 3:
dwelch67 wrote:Yes absolutely for this type of arm you need to set the various stack pointers for the different modes, and the "standard" way of doing this is somewhere in bootstrap you switch modes and set the stack pointer, I may or may not have anything like that in my examples but you see it done in other folks code.
Thanks for the advice, I'll try to find more docs and codes.

Question 4:

This is all my fault, I've already found my mistake and clarified it in the first reply. According to my new calculation, the limitation of the memory space should be 0x1C000000 instead of 0x07000000.

So
dwelch67 wrote:as far as your other question about 0x08000000 if it is my code maybe that is a bug or would have to research where I got that number, or someone else may answer that...
Yes, it is your code but, no, there is no problem with your code, but with my calculations. I'm sorry for my mistake =(

Furthermore:
AndrewS wrote:The 'kernel_address' option in http://www.raspberrypi.org/documentatio ... fig-txt.md if you're wondering how to change it... ;)
Thanks! I think it is a good solution to put the IVT at 0x0000.
P.S.: It seems that kernel_old=1 also helps.

Cheers!
xiguawanou

rst
Posts: 453
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: Questions about 0x8000, interrupts and memory structure

Wed Aug 27, 2014 6:34 pm

I would suggest to define a simple memory map in a .h file like this:

Code: Select all

/*
 * memmap.h
 */
#ifndef _memmap_h
#define _memmap_h

#define MEGABYTE		0x100000

/* sizes */
#define KERNEL_MAX_SIZE		(2 * MEGABYTE)
#define KERNEL_STACK_SIZE	0x10000
#define IRQ_STACK_SIZE		0x1000

/* memory map */
#define KERNEL_START		0x8000
#define KERNEL_END		(KERNEL_START + KERNEL_MAX_SIZE)

#define KERNEL_STACK_TOP	(KERNEL_END + KERNEL_STACK_SIZE)
#define IRQ_STACK_TOP		(KERNEL_STACK_TOP + IRQ_STACK_SIZE)

#define FREE_MEM		IRQ_STACK_TOP

#endif
Of course you can use it from C and C++ code but also from GNU assembler if you give your files a .S extension and call the assembler via GCC:

Code: Select all

arm-none-linux-gnueabi-gcc -c -o startup.o startup.S
Use the symbols from the memory map above in your assembly language files:

Code: Select all

/*
 * startup.S
 */
#include <memmap.h>

	.text

	.globl	_start
_start:
	mov	sp, #KERNEL_STACK_TOP
	...
It is also possible to initialize the IRQ stack at the beginning of the IRQ handler. It is not required to do this in the system init code.

Rene

xiGUAwanOU
Posts: 7
Joined: Sat Aug 09, 2014 8:28 pm

Re: Questions about 0x8000, interrupts and memory structure

Mon Sep 01, 2014 11:15 am

Finally I've got my LED on with interrupts. \o/

However, if I:

1. load the kernel.img at 0x0000 (set the kernel_address=0 in CONFIG.TXT),
2. write the kernel.ld file like this:

Code: Select all

MEMORY {
  ram : ORIGIN = 0x0000, LENGTH = 0x1000
}

SECTIONS {
  .text : { *(.text*) } > ram
  .bss : { *(.bss*) } > ram
}
3. write following codes in my assembly file:

Code: Select all

.globl _start
_start:
  ldr pc, reset_handler
  ldr pc, undefined_handler
  ldr pc, swi_handler
  ldr pc, prefetch_handler
  ldr pc, data_handler
  ldr pc, unused_handler
  ldr pc, irq_handler
  ldr pc, fiq_handler
reset_handler:      .word reset
undefined_handler:  .word hang
swi_handler:        .word hang
prefetch_handler:   .word hang
data_handler:       .word hang
unused_handler:     .word hang
irq_handler:        .word irq
fiq_handler:        .word hang

reset:
  mov r0, #(IRQ_MOD|DISABLE_IRQ|DISABLE_FIQ)
  msr cpsr_c, r0
  mov sp, #IRQ_STACK_TOP

/*** more codes goes here ***/
I didn't do any ldmia or stmia at the beginning of reset. And the sp of IRQ and FIQ is already at higher address rather than 0x8000 and 0x4000. But there is no success for me...

This is part of my kernel.list file:

Code: Select all

Disassembly of section .text:

00000000 <_start>:
   0:	e59ff018 	ldr	pc, [pc, #24]	; 20 <reset_handler>
   4:	e59ff018 	ldr	pc, [pc, #24]	; 24 <undefined_handler>
   8:	e59ff018 	ldr	pc, [pc, #24]	; 28 <swi_handler>
   c:	e59ff018 	ldr	pc, [pc, #24]	; 2c <prefetch_handler>
  10:	e59ff018 	ldr	pc, [pc, #24]	; 30 <data_handler>
  14:	e59ff018 	ldr	pc, [pc, #24]	; 34 <unused_handler>
  18:	e59ff018 	ldr	pc, [pc, #24]	; 38 <irq_handler>
  1c:	e59ff018 	ldr	pc, [pc, #24]	; 3c <fiq_handler>

00000020 <reset_handler>:
  20:	00000040 	.word	0x00000040

00000024 <undefined_handler>:
  24:	00000068 	.word	0x00000068

       :       :
       :       :

/*** more jump lists ***/

       :       :
       :       :

00000040 <reset>:
  40:	e3a000d2 	mov	r0, #210	; 0xd2
  44:	e121f000 	msr	CPSR_c, r0
  48:	e3a0d945 	mov	sp, #1130496	; 0x114000
  4c:	e3a000d1 	mov	r0, #209	; 0xd1
  50:	e121f000 	msr	CPSR_c, r0
  54:	e3a0d946 	mov	sp, #1146880	; 0x118000
  58:	e3a000d3 	mov	r0, #211	; 0xd3
  5c:	e121f000 	msr	CPSR_c, r0
  60:	e3a0d811 	mov	sp, #1114112	; 0x110000
  64:	eb000029 	bl	110 <cMain>
At last I tried 0x8000 and do ldmia and stmia at the beginning of reset, everything goes OK now. So why is it like this?

rst
Posts: 453
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: Questions about 0x8000, interrupts and memory structure

Mon Sep 01, 2014 12:09 pm

Please try to add disable_commandline_tags=1 to your config.txt file. The boot loader will otherwise overwrite your code at 0x100 with ATAGS.

BTW I think it's better to load the kernel at the default address 0x8000 and to create the vector table at 0x0 by some other method.

Rene

xiGUAwanOU
Posts: 7
Joined: Sat Aug 09, 2014 8:28 pm

Re: Questions about 0x8000, interrupts and memory structure

Mon Sep 01, 2014 12:29 pm

rst wrote:Please try to add disable_commandline_tags=1 to your config.txt file. The boot loader will otherwise overwrite your code at 0x100 with ATAGS.
Cool! Finally it works at 0x0000. Thanks for the answer. Btw. thanks for many advices, I'll take them.

rst
Posts: 453
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: Questions about 0x8000, interrupts and memory structure

Mon Sep 01, 2014 6:59 pm

xiGUAwanOU wrote:Cool! Finally it works at 0x0000. Thanks for the answer. Btw. thanks for many advices, I'll take them.
Fine. :D

dwelch67
Posts: 966
Joined: Sat May 26, 2012 5:32 pm

Re: Questions about 0x8000, interrupts and memory structure

Wed Sep 03, 2014 7:12 pm

I think the advice we are trying to give is:

so the tradeoff is if you build your binary to be loaded at 0x8000 you dont need any config.txt stuff, it just loads and runs. IF you want to handle any exceptions though (interrupts, etc) then you have to setup the exception area, I have an example or few that show how to make this pretty easy. Except for early versions before hardly anyone had a pi, the no config.txt pretend you are a linux kernel is just to use the 0x8000 no config.txt approach. This is the most tested and used case and part of why I use it.

If you go with a config.txt approach you have to keep up with the changes that happen to config.txt or find all the things (not clobbering your program with atags, etc). this may or may not have settled down but for a bit there keeping a 0x0000 based boot working with config.txt changes was not as easy as just not using a config.txt.

you could make a 0x0000 based binary that just has a branch and 0x8000-4 bytes of fill so they can clobber it as they wish, etc. but you still have to make sure you and anyone you share with uses the right config.txt settings.

The bottom line, I recommend you try both approaches the 0x8000 no .txt approach and the 0x0000 with .txt approach...Dont just take the first thing you get working and stick with it...

David

Return to “Bare metal, Assembly language”