colinh
Posts: 94
Joined: Tue Dec 03, 2013 11:59 pm
Location: Munich

Porting code from Pi Model B to Pi 2 (or Pi 3)

Sun Aug 13, 2017 3:09 pm

A couple of years ago I was writing a hobby OS (in assembly) for the Pi Model B. Then my JTAG interface broke and I discovered Torlus' patched QEMU -- which worked really well and was very convenient. At just about the time the Pi 2 was released (and Torlus's patches were merged into the mainstream QEMU) I stopped coding. I can't even remember why now...

Anyway, I've just started looking at it again and found that QEMU is actually emulating the Pi 2. So I'm finding myself having to modify my code...

Is there a list somewhere of everything that needs changing/considering?

1. Peripherals base addresses have moved from 0x20... to 0x3F...
2. ARM Physical to Bus address changes?
3. Board LED pin number
4. Interrupts?
5. Timers?
6. Multiple processors...
7. MMU/cache ?
8. DMA?

I downloaded the new ARMv7-A ARM and the Cortex A7 TRM and BCM2836 Q7 docs.

My very first thought was that of The Bowl of Petunias.

On the other hand, my interest is piqued...

So far, I just made the 0x20 to 0x3F changes, and the memory address jiggling to get the framebuffer to work...

I connect to a terminal/shell via the PL011 UART. That's not working. Any rough ideas where I need to start (reading)?

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

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Sun Aug 13, 2017 4:29 pm

You will need to first drop the core from HYP mode to SVC the park cores 1,2,3 as you now have 4 cpu's. Then core0 basically looks like a Pi1.
So plug this assembler in as first up add your current code after it.

Code: Select all

.balign	4
.globl _start
;@"================================================================"
;@ GetCPU out of HYP mode so it looks like a Pi 1
;@"================================================================"
#define CPU_SVCMODE 0x13				// CPU in SVC mode
#define CPU_HYPMODE 0x1A				// CPU in HYP mode
#define I_Bit  (1 << 7)						// Irq flag bit in cpsr (CPUMODE register)
#define F_Bit  (1 << 6)						// Fiq flag bit in cpsr (CPUMODE register)
_start:
    mrs r0,cpsr							;@ Fetch the cpsr register which includes CPU mode bits 
    and r1, r0, #0x1F						;@ Mask off the CPU mode bits to register r1                            
    cmp r1, #CPU_HYPMODE				;@ Check we are in HYP_MODE											
    bne .NotInHypMode						;@ Branch if not equal meaning was not in HYP_MODE  
    bic r0,r0,#0x1F							;@ Clear the CPU mode bits in register r0							
    orr r0, r0, #CPU_SVCMODE | I_Bit | F_Bit      ;@ Logical OR SVC_MODE bits onto register with Irq/Fiq disabled	
    msr spsr_cxsf,r0						;@ Hold value in spsr_cxsf
    add lr,pc,#4							;@ Calculate address of .NotInHypMode label    
    msr ELR_hyp, lr							;@ Set the address to ELR_hyp
    eret								        ;@  Elevated return which will exit at .NotInHypMode in SVC_MODE
.NotInHypMode:
;@"================================================================"
;@ Now park Core 1,2,3 into deadloop
;@"================================================================"
	mrc p15, 0, r0, c0, c0, 5				;@ Read core id on ARM7 & ARM8
	ands r0, r0, #0x3					        ;@ Make core 2 bit bitmask in R0
	beq  .cpu0_exit_multicore_park			;@ Core 0 jumps out
SecondarySpinDeadloop:
	b    SecondarySpinDeadloop 		       ;@ deadloop secondary spin
.cpu0_exit_multicore_park:
;@"================================================================"
;@  You now have core 0 and it looks sort of like a Pi1
;@"================================================================"
/* old code goes here */
Address change which you have done and ARM to VC address is 0xC0000000 as opposed to 0x40000000.

That is all ..... your old code should work after that.

colinh
Posts: 94
Joined: Tue Dec 03, 2013 11:59 pm
Location: Munich

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Mon Aug 14, 2017 11:27 pm

Hi. Thanks for the code. Just a couple of remarks:


As might be expected from ARM v7-A ARM, in section B1.9.1 Reset the processor seems to be booting in SVC mode (at least under QEMU); CPSR was 0x400001D3 (after the mrs r0,cpsr instruction at _start:), ie the last 5 bits are 1.0011.

And from this viewtopic.php?f=72&t=98904&start=25#p700528 it appears that the other cores are already parked in tight loops.

This code shows that indeed only core 0 is running:

Code: Select all

NotInHypMode:
   mrc   p15,0,r0,r0,r0,5
   ldr   r1, =init_info
   and   r2, r0, #03
   str   r0, [r1, r2, lsl #2]

colinh
Posts: 94
Joined: Tue Dec 03, 2013 11:59 pm
Location: Munich

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Tue Aug 15, 2017 2:46 am

OK, so all I actually needed to do was change the peripherals base, and jiggle the framebuffer address. That's it.


Anyone want to laugh at why "it still Wasn't Working(TM)"?

I started qemu like this:

qemu-system-arm -kernel kernel.img -cpu cortex-a7 -m 512 -smp cores=4 -machine raspi2 -serial stdio

Then the qemu window pops up with the contents of the framebuffer. The qemu window is active. I click inside it and qemu grabs the mouse and keyboard input.

I type and nothing happens.

I read 4000 pages of documentation. And many old blog posts etc.

Then, one day, I click in the terminal I ran the qemu command from and type a bit --- and it appears in my terminal window in the framebuffer of my emulated hobby OS! Like it's supposed to! Everything works!

Aaaargh! :roll:

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

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Tue Aug 15, 2017 6:51 am

Not sure how the emulation of QEMU works but on most true baremetal newlib implementations you don't get anything until you hit a CR or LF or flush the buffer.

So usually this does nothing it's just sitting in the buffer
printf("hello");

This will fire out hello as the buffer gets flushed out
printf("hello\n");

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

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Tue Aug 15, 2017 1:35 pm

only if using a printf and library like newlib does it not flush until a crlf if talking to the uart yourself then it should just spill out per character.

I cant say the MMU and interrupts just port over directly. are you booting from zero with a config.txt or letting them boot you at 0x8000? you will be in hyp mode not SVC and your interrupts have to change can be as simple as an eret instead of sub pc,lr,#4 or whatever it is. I dont remember if I looked into the mmu on armv7, hmmm...yeah dont think I have, I assume there are changes with the additional protection mechanisms, but also they may have a compatibility/legacy mode...dont know would have to look. if pi3 then aarch32 or aarch64? aarch64 brings a whole new level of fun and likely changes to your software, depending on your design might be limited to some low level stuff in isolated areas, but again depends on how your OS/software was designed (how much of it is generic, target independent, and how much target dependent).

one nice thing about qemu uarts, is I have found them to be lazy and you can just write to the data port and a character pops out, sometimes without any initialization, and without any checking for the tx buffer to be empty. but each is written by a different person so YMMV. point being you could have your boostrap pop a byte out for sanity (although the console may not be up in time to see it). and maybe your system timer interrupt for task switching or other operating system maintenance can pop a byte out the uart by just writing to the tx register, look for signs of life that way...would start with a 5-10 line asm program to see if this works or not (an infinite loop blasting characters) before infecting your main source code with this temporary debug test

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

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Tue Aug 15, 2017 1:36 pm

and the leds moved around from time to time but the last p1's to the p2 might be common, the pi3 is not on a gpio pin but you could put your own led (plus resistor) on a gpio pin and blink it as needed.

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

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Tue Aug 15, 2017 1:43 pm

He is on QEMU David not a real Pi2 .. so I am guessing he has no option but to boot from 0x0 and be in SVC mode. I doubt they have the bootloader stub active on an emulator.

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

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Tue Aug 15, 2017 2:18 pm

duh, yeah didnt think about that, although someone could easily write the code to do that bootstrap as well as write code to replace the rest of the gpu functionality (frame buffer, mailbox handling, etc).

colinh
Posts: 94
Joined: Tue Dec 03, 2013 11:59 pm
Location: Munich

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Tue Aug 15, 2017 11:43 pm

The ARM1176JZF-S being ARMv6 with loads of extensions, I think we were supposed to be using the ARMv7-A ARM anyway, no? At least, that's what I think I did for the MMU/cache setup. The only other ARM ARM I have is DDI 100I, which (I think) is for ARMv5. There is no ARMv6-A ARM.

Yes, there's no config.txt (and no LEDs either :-( ) so it does indeed boot from 0x00000000. (when I was running on a real Pi Model B, I used kernel_old=1).

I actually have _start at 0x10000.

There's some stub loaded at 0x00000000 (not put there by me), (but comments by me):

Code: Select all

   0x00000000:	04 e0 8f e2	add	lr, pc, #4			// set LR to 0x0000000c
   0x00000004:	04 f0 1f e5	ldr	pc, [pc, #-4]	; 0x8		// load PC with contents of 0x00000008, ie jump to 0x420
   0x00000008:	20 04 00 00	andeq	r0, r0, r0, lsr #8
   0x0000000c:	00 00 a0 e3	mov	r0, #0				// (return here)
   0x00000010:	04 10 9f e5	ldr	r1, [pc, #4]	; 0x1c		// r1 = 0x00000c43
   0x00000014:	04 20 9f e5	ldr	r2, [pc, #4]	; 0x20		// r2 = 0x00000100
   0x00000018:	04 f0 9f e5	ldr	pc, [pc, #4]	; 0x24		// jump to 0x00010000
   0x0000001c:	43 0c 00 00	andeq	r0, r0, r3, asr #24
   0x00000020:	00 01 00 00	andeq	r0, r0, r0, lsl #2
   0x00000024:	00 00 01 00	andeq	r0, r1, r0

   ...
   
   0x00000420:	40 0e a0 e3	mov	r0, #64, 28	; 0x400
   0x00000424:	30 0f 0c ee	mcr	15, 0, r0, cr12, cr0, {1}	// set MON vector base addr to 0x40
   0x00000428:	11 0f 11 ee	mrc	15, 0, r0, cr1, cr1, {0}	// r0 = SCR, Secure Configuration Register, Security Extensions
   0x0000042c:	31 00 80 e3	orr	r0, r0, #49	; 0x31		// set AW, FW and NS bits (see ARMv7-A ARM, B4-1705)
   0x00000430:	11 0f 01 ee	mcr	15, 0, r0, cr1, cr1, {0}	// write SCR
   0x00000434:	0e 10 a0 e1	mov	r1, lr				// save LR in r1
   0x00000438:	70 00 60 e1	smc	0				// generate Secure Monitor Call exception
   0x0000043c:	01 f0 a0 e1	mov	pc, r1				// jump back to 0x0000000C

So, I copy my vector table down to 0x00000000 myself. I try to keep things as close to ARMv2 as I can :-)

edit: Duh. I just remembered that from gdb I set pc=0x00010000 before I start single stepping or whatever. So none of that gets executed.

edit2: Oh. The ARM ARM (DDI 100I) makes a reference to ARMv6. And comments in my code refer to it. I must have used both docs. I haven't compared the MMU sections.

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

Re: Porting code from Pi Model B to Pi 2 (or Pi 3)

Wed Aug 16, 2017 1:19 pm

If you are porting from the pi1 to pi2 or pi3, assuming 32 bit or AARCH32 then that means armv7-a for the pi2 and a compatibility mode for the pi3.

So you need both the armv5 ARM ARM, yes they dont have an armv6 one. there used to be just one armv4 then armv5 stuff added, then a little armv6 and no doubt became obvious one doc wasnt going to cut it from the beginning of (ARM) time to the present so the various other ARM ARM's started to show up. and the armv7-a one so you can compare pi1 to pi2.

Very quick glance the basic mmu table structure is the same, the armv6 (and older) bits are still there and at least have the same labels. But some of the SBZs have become additional property bits, so you would have to read up on those one would hope that if zero they behave in a legacy way

David

Return to “Bare metal”

Who is online

Users browsing this forum: No registered users and 5 guests