gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Getting a framebuffer

Mon Jun 12, 2017 4:24 pm

Hi!

My friend and I are making a bare metal project on a Raspberry PI 3. We've gotten GPIO and the system timer to work and now we are trying to implement graphics with a framebuffer. We have looked at https://www.cl.cam.ac.uk/projects/raspb ... een01.html and https://github.com/brianwiddas/pi-barem ... mebuffer.c but can't get it to work. The usual rainbow screen shows up but we are not able to put something else on the screen.

Here is our framebuffer code:
framebuffer.h:

Code: Select all

#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H

typedef struct {
	void* pointer;
	unsigned int width;
	unsigned int height;
	unsigned int depth;
} FrameBuffer;

/**
 * Should only be run once.
 * Returns a pointer to a struct containing
 * information about the framebuffer.
 */
FrameBuffer* fb_init(int depth);

#endif
framebuffer.c

Code: Select all

#include "framebuffer.h"
#include "constants.h"
#include "mailbox.h"

typedef struct {
	unsigned int msg_size;
	unsigned int request;
	unsigned int tag;
	unsigned int buffer_size;
	unsigned int request_size;
	unsigned int width;
	unsigned int height;
	unsigned int end;
} DisplaySizeMessage;

typedef struct {
	unsigned int pwidth;
	unsigned int pheight;
	unsigned int vwidth;
	unsigned int vheight;
	unsigned int pitch;
	unsigned int depth;
	unsigned int x;
	unsigned int y;
	unsigned int pointer;
	unsigned int size;
} FrameBufferInfo;

static FrameBuffer* buffer = (FrameBuffer*) STATIC_VARS;
extern volatile  DisplaySizeMessage* disp_size;
extern volatile FrameBufferInfo* fb_info;
	
FrameBuffer* fb_init(int depth){
	unsigned int response;
	
	// Ta reda på skärmens upplösning
	
	if (!mailbox_write(PROPERTY_TAGS1, (unsigned int) mailbox_ARM_to_VC((void*) &disp_size))) {
		return (FrameBuffer*) 0;
	}
	response = mailbox_read(PROPERTY_TAGS1);
	
	if (disp_size->request != 0x80000000) {
		return (FrameBuffer*) 0;
	}
	
	fb_info->pwidth = fb_info->vwidth = disp_size->width;
	fb_info->pheight = fb_info->vheight = disp_size->height;
	fb_info->depth = depth;
	
	if (!mailbox_write(FRAMEBUFFER, (unsigned int) mailbox_ARM_to_VC((void*) &fb_info))) {
		return (FrameBuffer*) 0;
	}
	response = mailbox_read(FRAMEBUFFER);
	if (response != 0) {
		return (FrameBuffer*) 0;
	}
	
	buffer->pointer = (void*) fb_info->pointer;
	buffer->width = disp_size->width;
	buffer->height = disp_size->height;
	buffer->depth = depth;
	
	return buffer;
}
mailbox.h

Code: Select all

#ifndef MAILBOX_H
#define MAILBOX_H

#include "constants.h"

#define MAILBOX_BASE (IO_BASE + 0xB880)
#define STATUS_OFFSET 0x18
#define WRITE_OFFSET 0x20


typedef enum {
	POWER_MANAGEMENT = 0,
	FRAMEBUFFER = 1,
	VIRUTAL_UART = 2,
	VCHIQ = 3,
	LEDS = 4,
	BUTTONS = 5,
	TOUCH_SCREEN = 6,
	PROPERTY_TAGS1 = 8,
	PROPERTY_TAGS2 = 9
} channel;

unsigned int mailbox_read(channel c);

int mailbox_write(channel c, unsigned int msg);

/*
 * Translates address according to https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html and https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes.
 */
void* mailbox_ARM_to_VC(void* ptr);

#endif
mailbox.c

Code: Select all

#include "mailbox.h"

unsigned int mailbox_read(channel c) {
	// Kolla att giltig kanal
	if ((c < 0) || (c > 9) || (c == 7)) {
		return 0;
	}
	
	volatile unsigned int* box = (unsigned int*) MAILBOX_BASE;
	volatile unsigned int* status = box + STATUS_OFFSET;
	unsigned int data;
	
	while (1) {
		while ((*status & 0x40000000) != 0) {}
		
		data = *box;
		if ((data & c) == c) {
			break;
		}
	}
	
	return data & 0xFFFFFFF0;
}

int mailbox_write(channel c, unsigned int msg) {
	// Kolla att giltig kanal
	if ((c < 0) || (c > 9) || (c == 7)){
		return 0;
	}
	// Kolla att 4 minst signifikanta bitar är 0
	if ((msg & 0xF) != 0){
		return 0;
	}
	
	volatile unsigned int* box = (unsigned int*) MAILBOX_BASE;
	volatile unsigned int* status = box + STATUS_OFFSET;
	volatile unsigned int* write = box + WRITE_OFFSET;
	
	// Vänta tills mest signifikanta biten är 0.
	// Då är mailboxen redo att ta emot meddelande.
	while ((*status & 0x80000000) != 0) {}
	
	*write = msg | c;

	return 1;
}

void* mailbox_ARM_to_VC(void* ptr) {
	return ptr + 0x40000000;
}
IO_BASE has the value 0x3F000000 and STATIC_VARS has the value 0x10000 and we plan to place variables that have to be able to be globally accessible there. We have been banging our heads for several hours and have run out of ideas. Some help would be much appreciated!

EDIT 1: This is how we use the framebuffer after it is acquired:

Code: Select all

#include "framebuffer.h"
#include "GPIO.h"
#include "time.h"

void kernelmain() {
	int led = 2;
	
	gpio_setup(led, OUTPUT);
	gpio_output(led, LOW);
        // Wait some time to let the rainbow show up and so that the LED turns off
	sleep(10000000); // Sleep takes microseconds as input (10s)
	gpio_output(led, HIGH);
	
	FrameBuffer* buffer = fb_init(16);
	if (!buffer) {
		gpio_output(led, LOW);
		return;
	}
	
	short* fb = (short*) buffer->pointer;
	
        // Write some random colors to the screen.
	for (int i = 0; i < (buffer->width*buffer->height); i++) {
		fb[i] = i;
	}
}
EDIT 2: This is the code that defines disp_size and fb_info:

Code: Select all

.data

.global disp_size
.global fb_info

.align 16

disp_size:
	.int 32      // msg_size
	.int 0       // requesst
	.int 0x40003 // tag
	.int 8       // buffer_size
	.int 0       // request_size
	.int 0       // width
	.int 0       // height
	.int 0       // end

.align 16

fb_info:
	.int 0  // PWidth
	.int 0  // PHeight
	.int 0  // VWidth
	.int 0  // VHeight
	.int 0  // pitch
	.int 0  // depth
	.int 0  // X
	.int 0  // Y
	.int 0  // Pointer
	.int 0  // GPU-Size

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

Re: Getting a framebuffer

Mon Jun 12, 2017 5:18 pm

We just did all that 4 posts ago .. lots of code and discussion about things you can get wrong there

viewtopic.php?f=72&t=185116

Make sure your firmware is up todate.
https://github.com/raspberrypi/firmware ... aster/boot.

Makogan
Posts: 71
Joined: Tue May 16, 2017 9:17 pm

Re: Getting a framebuffer

Mon Jun 12, 2017 9:14 pm

I remember :p

Makogan
Posts: 71
Joined: Tue May 16, 2017 9:17 pm

Re: Getting a framebuffer

Mon Jun 12, 2017 9:36 pm

As an immediate short reply I can tell you the following:

The framebuffer initialisation structure must be contiguous in memory with all tags. In other words it is recommended you create 1 big structure with:

The physical display tag and it's relevant parts, the virtual display tag and it's relevant parts, the depth tag and it's relevant parts, the allocate tag and it's relevant parts. Despite what the documentation says, you must Use the Arm_to_VC channel (channel 8) and you must send and receive the addresses as seen by the videocore through the BUS (i.e or with 0xC0000000 when sending and do AND ~0xC0000000 when receiving)

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Tue Jun 13, 2017 12:09 pm

Thank you for the answers! It is very annoying that the documentation is wrong. I'll try with this new information and check if it works better.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Tue Jun 13, 2017 4:37 pm

We have tried and still no luck. Recently, reading from the mailbox results in an infinite loop which didn't happen before. We are very confused.

framebuffer.c:

Code: Select all

#include "framebuffer.h"
#include "constants.h"
#include "mailbox.h"

FrameBuffer* buffer = (FrameBuffer*) STATIC_VARS;
extern volatile  DisplaySizeMessage disp_size;
extern volatile unsigned int fb_info;
	
FrameBuffer* fb_init(int depth){
	unsigned int response;

	volatile unsigned int* finfo = &fb_info;
	
	finfo[5] = 1280;//disp_size.width;
	finfo[6] = 800;//disp_size.height;
	finfo[10] = 1280;//disp_size.width;
	finfo[11] = 800;//disp_size.height;
	finfo[15] = depth;
	
	if (!mailbox_write(PROPERTY_TAGS1, (unsigned int) mailbox_ARM_to_VC((void*) &fb_info))) {
		return (FrameBuffer*) 0;
	}
	
	response = mailbox_read(PROPERTY_TAGS1);
	if (response != 0) {
		return (FrameBuffer*) 0;
	}
	
	buffer->pointer = mailbox_VC_to_ARM((void*) finfo[20]);
	buffer->width = 1280;//disp_size.width;
	buffer->height = 800;//disp_size.height;
	buffer->depth = depth;
	
	return buffer;
}
mailbox.c:

Code: Select all

#include "mailbox.h"

unsigned int mailbox_read(channel c) {
	// Kolla att giltig kanal
	if ((c < 0) || (c > 9) || (c == 7)) {
		return 0;
	}
	
	volatile unsigned int* box = (unsigned int*) MAILBOX_BASE;
	volatile unsigned int* status = box + STATUS_OFFSET;
	unsigned int data;
	
	while (1) {
		while ((*status & 0x40000000) != 0) {}
		
		data = *box;
		if ((data & 0xF) == c) { // This is never true so the code gets stuck here
			break;
		}
	}
	
	return data & ~(0xF);
}

int mailbox_write(channel c, unsigned int msg) {
	// Kolla att giltig kanal
	if ((c < 0) || (c > 9) || (c == 7)){
		return 0;
	}
	// Kolla att 4 minst signifikanta bitar är 0
	if ((msg & 0xF) != 0){
		return 0;
	}
	
	volatile unsigned int* box = (unsigned int*) MAILBOX_BASE;
	volatile unsigned int* status = box + STATUS_OFFSET;
	volatile unsigned int* write = box + WRITE_OFFSET;
	
	// Vänta tills mest signifikanta biten är 0.
	// Då är mailboxen redo att ta emot meddelande.
	while ((*status & 0x80000000) != 0) {}
	
	*write = msg | c;

	return 1;
}

void* mailbox_ARM_to_VC(void* ptr) {
	return (void*) ((unsigned int) ptr | 0xC0000000);
}

void* mailbox_VC_to_ARM(void* ptr) {
	return (void*) ((unsigned int) ptr & (~0xC0000000));
}
Definition of fb_info:

Code: Select all

.align 16

fb_info:
	.int 136        //tot msg siz
	.int 0    		//request (1)
	
	.int 0x48003 //tag_id set physical
	.int 8 			//value_buf_size
	.int 8			//requst + value_buf
	.int 0			//horizontal rez
	.int 0			//Vert rez (6)
	
	.int 0x48004 //tag_id virtual
	.int 8 			//value_buf_size
	.int 8			//requst + value_buf
	.int 0			//horizontal rez
	.int 0			//Vert rez (11)

	.int 0x48005 //tag_id vset depth
	.int 4 			//value_buf_size
	.int 4			//requst + value_buf
	.int 0			//depth(15)
	
	.int 0x40001 // alloc framebuffer
	.int 8			//value_buf_size
	.int 4			//requst + value_buf
	.int 16			//alignment
	.int 0			//Space for response(20)
	
	.int 0			//end(21)

Makogan
Posts: 71
Joined: Tue May 16, 2017 9:17 pm

Re: Getting a framebuffer

Tue Jun 13, 2017 6:19 pm

Why is your size 136? Your message is 22 bytes.

I don't want to sound like a dick, but... We solved this for the pi 3 (I was the one asking and having troubles) and I guarantee it works now. Go to the post LDB linked, if you still have trouble my github is linked there as well and you can look at the code and how I did things.

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

Re: Getting a framebuffer

Wed Jun 14, 2017 6:57 am

Which is why there is no response .. it just posted 124 of random data to the VC via the mailbox.

It is an interesting aside that the mailbox system seems to have no way to tell you ..... message garbage go to hell.

Each tag has an fail/success response but the packed message system itself seems to have no safety. I have not seen any code that can survive sending the wrong data size because they are looped on the channel response as per the read sample provided on the wiki ...
https://github.com/raspberrypi/firmware ... -mailboxes
Which is exactly the same loop as above and it would die in exactly the same place.

All we can say is take more care because there is scant safety on it.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Wed Jun 14, 2017 12:05 pm

Why is your size 136? Your message is 22 bytes.
Don't know where I got 136 from, changed it to 88 (22*4).
We solved this for the pi 3 (I was the one asking and having troubles) and I guarantee it works now. Go to the post LDB linked, if you still have trouble my github is linked there as well and you can look at the code and how I did things.
I have read the linked thread and your code on github. I think your code and mine look identical but I still have the same problem. I have tried your approach too of defining the message in C instead of assembly but it did not work either. There is probably some really stupid mistake somewhere.

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

Re: Getting a framebuffer

Wed Jun 14, 2017 1:17 pm

Try the minimal boot .. I know you had it running with the GPIO ... lessons from school of hard knocks :-).

Can you also show us a map file output so we know your linker directive file is okay.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Wed Jun 14, 2017 2:51 pm

Tried adding the code int boot.S that enables FPU and L1 cache etc. but now my main function isn't even executed. I can see this because on power up a connected LED is faintly glowing and the code starts by turning the LED off. This doesn't happen anymore.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Wed Jun 14, 2017 3:11 pm

Now it works again. Don't know what happened. I still have the same problem with the mailbox though.

EDIT: I am not entirely familiar with map file but I think this may be what you asked for:

Code: Select all

Memory Configuration

Name             Origin             Length             Attributes
*default*        0x0000000000000000 0xffffffffffffffff

Linker script and memory map


.init           0x0000000000008000        0xc
 *(.init)
 .init          0x0000000000008000        0xc main.o

.text           0x000000000000800c      0x7fc
 *(.text)
 .text          0x000000000000800c       0x94 framebuffer.o
                0x000000000000800c                fb_init
 .text          0x00000000000080a0        0x0 framebufferstruct.o
 .text          0x00000000000080a0       0xf8 GPIO.o
                0x00000000000080a0                gpio_setup
                0x00000000000080ec                gpio_output
                0x000000000000816c                gpio_input
 .text          0x0000000000008198       0xa8 kernel.o
                0x0000000000008198                kernelmain
 .text          0x0000000000008240       0xcc mailbox.o
                0x0000000000008240                mailbox_read
                0x00000000000082a4                mailbox_write
                0x00000000000082fc                mailbox_ARM_to_VC
                0x0000000000008304                mailbox_VC_to_ARM
 .text          0x000000000000830c        0x0 main.o
 .text          0x000000000000830c       0xcc math.o
                0x000000000000830c                __aeabi_idiv
                0x00000000000083c4                abs
                0x00000000000083d0                sign
 .text          0x00000000000083d8      0x128 memory.o
                0x00000000000083d8                memset
 .text          0x0000000000008500      0x248 morse.o
                0x0000000000008500                morse_blink
                0x00000000000085f4                morse_code
                0x0000000000008644                morse_code_blink
                0x00000000000086d8                morse_short
                0x0000000000008710                morse_long
 .text          0x0000000000008748       0x90 string.o
                0x0000000000008748                strlen
                0x0000000000008778                toUpper
                0x00000000000087a8                toLower
 .text          0x00000000000087d8       0x30 time.o
                0x00000000000087d8                time
                0x00000000000087e8                sleep

.rodata         0x0000000000008808       0xdc
 .rodata        0x0000000000008808       0xdc morse.o
                0x0000000000008808                MORSESYMBOLS
                0x00000000000088e0                NCHARS

.rodata.str1.4  0x00000000000088e4       0x28
 .rodata.str1.4
                0x00000000000088e4       0x28 morse.o
                                         0x29 (size before relaxing)

.glue_7         0x000000000000890c        0x0
 .glue_7        0x000000000000890c        0x0 linker stubs

.glue_7t        0x000000000000890c        0x0
 .glue_7t       0x000000000000890c        0x0 linker stubs

.vfp11_veneer   0x000000000000890c        0x0
 .vfp11_veneer  0x000000000000890c        0x0 linker stubs

.v4_bx          0x000000000000890c        0x0
 .v4_bx         0x000000000000890c        0x0 linker stubs

.iplt           0x000000000000890c        0x0
 .iplt          0x000000000000890c        0x0 framebuffer.o

.rel.dyn        0x000000000000890c        0x0
 .rel.iplt      0x000000000000890c        0x0 framebuffer.o

.data           0x0000000000010000    0x2005c
 *(.data)
 .data          0x0000000000010000        0x4 framebuffer.o
                0x0000000000010000                buffer
 *fill*         0x0000000000010004     0xfffc 
 .data          0x0000000000020000    0x10058 framebufferstruct.o
                0x0000000000020000                disp_size
                0x0000000000030000                fb_info
 .data          0x0000000000030058        0x0 GPIO.o
 .data          0x0000000000030058        0x0 kernel.o
 .data          0x0000000000030058        0x0 mailbox.o
 .data          0x0000000000030058        0x0 main.o
 .data          0x0000000000030058        0x0 math.o
 .data          0x0000000000030058        0x0 memory.o
 .data          0x0000000000030058        0x4 morse.o
                0x0000000000030058                CHARACTERS
 .data          0x000000000003005c        0x0 string.o
 .data          0x000000000003005c        0x0 time.o
LOAD framebuffer.o
LOAD framebufferstruct.o
LOAD GPIO.o
LOAD kernel.o
LOAD mailbox.o
LOAD main.o
LOAD math.o
LOAD memory.o
LOAD morse.o
LOAD string.o
LOAD time.o
OUTPUT(out.elf elf32-littlearm)

.igot.plt       0x000000000003005c        0x0
 .igot.plt      0x000000000003005c        0x0 framebuffer.o

.bss            0x000000000003005c        0x0
 .bss           0x000000000003005c        0x0 framebuffer.o
 .bss           0x000000000003005c        0x0 framebufferstruct.o
 .bss           0x000000000003005c        0x0 GPIO.o
 .bss           0x000000000003005c        0x0 kernel.o
 .bss           0x000000000003005c        0x0 mailbox.o
 .bss           0x000000000003005c        0x0 main.o
 .bss           0x000000000003005c        0x0 math.o
 .bss           0x000000000003005c        0x0 memory.o
 .bss           0x000000000003005c        0x0 morse.o
 .bss           0x000000000003005c        0x0 string.o
 .bss           0x000000000003005c        0x0 time.o

.comment        0x0000000000000000       0x2b
 .comment       0x0000000000000000       0x2b framebuffer.o
                                         0x2c (size before relaxing)
 .comment       0x000000000000002b       0x2c GPIO.o
 .comment       0x000000000000002b       0x2c kernel.o
 .comment       0x000000000000002b       0x2c mailbox.o
 .comment       0x000000000000002b       0x2c math.o
 .comment       0x000000000000002b       0x2c memory.o
 .comment       0x000000000000002b       0x2c morse.o
 .comment       0x000000000000002b       0x2c string.o
 .comment       0x000000000000002b       0x2c time.o

.ARM.attributes
                0x0000000000000000       0x33
 .ARM.attributes
                0x0000000000000000       0x35 framebuffer.o
 .ARM.attributes
                0x0000000000000035       0x21 framebufferstruct.o
 .ARM.attributes
                0x0000000000000056       0x35 GPIO.o
 .ARM.attributes
                0x000000000000008b       0x35 kernel.o
 .ARM.attributes
                0x00000000000000c0       0x35 mailbox.o
 .ARM.attributes
                0x00000000000000f5       0x21 main.o
 .ARM.attributes
                0x0000000000000116       0x35 math.o
 .ARM.attributes
                0x000000000000014b       0x35 memory.o
 .ARM.attributes
                0x0000000000000180       0x35 morse.o
 .ARM.attributes
                0x00000000000001b5       0x35 string.o
 .ARM.attributes
                0x00000000000001ea       0x35 time.o
EDIT 2: Running objdump -x on framebufferstruct.o gives

Code: Select all

framebufferstruct.o:     file format elf32-littlearm
framebufferstruct.o
architecture: arm, flags 0x00000010:
HAS_SYMS
start address 0x00000000
private flags = 5000000: [Version5 EABI]

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00010058  00000000  00000000  00010000  2**16
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00020058  2**0
                  ALLOC
  3 .ARM.attributes 00000021  00000000  00000000  00020058  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
00000000 l    d  .text	00000000 .text
00000000 l    d  .data	00000000 .data
00000000 l    d  .bss	00000000 .bss
00000000 l    d  .ARM.attributes	00000000 .ARM.attributes
00000000 g       .data	00000000 disp_size
00010000 g       .data	00000000 fb_info

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

Re: Getting a framebuffer

Wed Jun 14, 2017 3:53 pm

Your init is 12 bytes??????
.init 0x0000000000008000 0xc
*(.init)
.init 0x0000000000008000 0xc main.o

Can I get a proper map please from the elf file .. the command you need a path to the executable (arm-none-eabi-nm) in front.

arm-none-eabi-nm kernel.elf > kernel.map

Then show me the file kernel.map

Can I really suggest you try the repository code as we need to narrow down what is happening :-)

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Wed Jun 14, 2017 4:22 pm

I have tried downloading the code from the repository, compile it and put it on the SD-card. It works perfectly. I see characters displayed on the screen.

Here is the result of the command:

Code: Select all

000083c4 T abs
0000830c T __aeabi_idiv
00010000 D buffer
00030058 D CHARACTERS
00020000 D disp_size
00030000 D fb_info
0000800c T fb_init
0000816c T gpio_input
000080ec T gpio_output
000080a0 T gpio_setup
00008198 T kernelmain
00010000 d .LANCHOR0
00030058 d .LANCHOR0
00008808 r .LANCHOR1
00008008 t loop
000082fc T mailbox_ARM_to_VC
00008240 T mailbox_read
00008304 T mailbox_VC_to_ARM
000082a4 T mailbox_write
000083d8 T memset
00008500 T morse_blink
000085f4 T morse_code
00008644 T morse_code_blink
00008710 T morse_long
000086d8 T morse_short
00008808 R MORSESYMBOLS
000088e0 R NCHARS
000083d0 T sign
000087e8 T sleep
00008748 T strlen
000087d8 T time
000087a8 T toLower
00008778 T toUpper
EDIT: My main.s was messed up. Here is the result of running ld with -Map and the result of nm:
ld

Code: Select all

Memory Configuration

Name             Origin             Length             Attributes
*default*        0x0000000000000000 0xffffffffffffffff

Linker script and memory map


.init           0x0000000000008000       0x48
 *(.init)
 .init          0x0000000000008000       0x48 main.o

.text           0x0000000000008048      0x7ec
 *(.text)
 .text          0x0000000000008048       0x94 framebuffer.o
                0x0000000000008048                fb_init
 .text          0x00000000000080dc        0x0 framebufferstruct.o
 .text          0x00000000000080dc       0xf8 GPIO.o
                0x00000000000080dc                gpio_setup
                0x0000000000008128                gpio_output
                0x00000000000081a8                gpio_input
 .text          0x00000000000081d4       0xa8 kernel.o
                0x00000000000081d4                kernelmain
 .text          0x000000000000827c       0xbc mailbox.o
                0x000000000000827c                mailbox_read
                0x00000000000082d0                mailbox_write
                0x0000000000008328                mailbox_ARM_to_VC
                0x0000000000008330                mailbox_VC_to_ARM
 .text          0x0000000000008338        0x0 main.o
 .text          0x0000000000008338       0xcc math.o
                0x0000000000008338                __aeabi_idiv
                0x00000000000083f0                abs
                0x00000000000083fc                sign
 .text          0x0000000000008404      0x128 memory.o
                0x0000000000008404                memset
 .text          0x000000000000852c      0x248 morse.o
                0x000000000000852c                morse_blink
                0x0000000000008620                morse_code
                0x0000000000008670                morse_code_blink
                0x0000000000008704                morse_short
                0x000000000000873c                morse_long
 .text          0x0000000000008774       0x90 string.o
                0x0000000000008774                strlen
                0x00000000000087a4                toUpper
                0x00000000000087d4                toLower
 .text          0x0000000000008804       0x30 time.o
                0x0000000000008804                time
                0x0000000000008814                sleep

.rodata         0x0000000000008838       0xdc
 .rodata        0x0000000000008838       0xdc morse.o
                0x0000000000008838                MORSESYMBOLS
                0x0000000000008910                NCHARS

.rodata.str1.4  0x0000000000008914       0x28
 .rodata.str1.4
                0x0000000000008914       0x28 morse.o
                                         0x29 (size before relaxing)

.glue_7         0x000000000000893c        0x0
 .glue_7        0x000000000000893c        0x0 linker stubs

.glue_7t        0x000000000000893c        0x0
 .glue_7t       0x000000000000893c        0x0 linker stubs

.vfp11_veneer   0x000000000000893c        0x0
 .vfp11_veneer  0x000000000000893c        0x0 linker stubs

.v4_bx          0x000000000000893c        0x0
 .v4_bx         0x000000000000893c        0x0 linker stubs

.iplt           0x000000000000893c        0x0
 .iplt          0x000000000000893c        0x0 framebuffer.o

.rel.dyn        0x000000000000893c        0x0
 .rel.iplt      0x000000000000893c        0x0 framebuffer.o

.data           0x0000000000010000    0x2005c
 *(.data)
 .data          0x0000000000010000        0x4 framebuffer.o
                0x0000000000010000                buffer
 *fill*         0x0000000000010004     0xfffc 
 .data          0x0000000000020000    0x10058 framebufferstruct.o
                0x0000000000020000                disp_size
                0x0000000000030000                fb_info
 .data          0x0000000000030058        0x0 GPIO.o
 .data          0x0000000000030058        0x0 kernel.o
 .data          0x0000000000030058        0x0 mailbox.o
 .data          0x0000000000030058        0x0 main.o
 .data          0x0000000000030058        0x0 math.o
 .data          0x0000000000030058        0x0 memory.o
 .data          0x0000000000030058        0x4 morse.o
                0x0000000000030058                CHARACTERS
 .data          0x000000000003005c        0x0 string.o
 .data          0x000000000003005c        0x0 time.o
LOAD framebuffer.o
LOAD framebufferstruct.o
LOAD GPIO.o
LOAD kernel.o
LOAD mailbox.o
LOAD main.o
LOAD math.o
LOAD memory.o
LOAD morse.o
LOAD string.o
LOAD time.o
OUTPUT(out.elf elf32-littlearm)

.igot.plt       0x000000000003005c        0x0
 .igot.plt      0x000000000003005c        0x0 framebuffer.o

.bss            0x000000000003005c        0x0
 .bss           0x000000000003005c        0x0 framebuffer.o
 .bss           0x000000000003005c        0x0 framebufferstruct.o
 .bss           0x000000000003005c        0x0 GPIO.o
 .bss           0x000000000003005c        0x0 kernel.o
 .bss           0x000000000003005c        0x0 mailbox.o
 .bss           0x000000000003005c        0x0 main.o
 .bss           0x000000000003005c        0x0 math.o
 .bss           0x000000000003005c        0x0 memory.o
 .bss           0x000000000003005c        0x0 morse.o
 .bss           0x000000000003005c        0x0 string.o
 .bss           0x000000000003005c        0x0 time.o

.comment        0x0000000000000000       0x2b
 .comment       0x0000000000000000       0x2b framebuffer.o
                                         0x2c (size before relaxing)
 .comment       0x000000000000002b       0x2c GPIO.o
 .comment       0x000000000000002b       0x2c kernel.o
 .comment       0x000000000000002b       0x2c mailbox.o
 .comment       0x000000000000002b       0x2c math.o
 .comment       0x000000000000002b       0x2c memory.o
 .comment       0x000000000000002b       0x2c morse.o
 .comment       0x000000000000002b       0x2c string.o
 .comment       0x000000000000002b       0x2c time.o

.ARM.attributes
                0x0000000000000000       0x33
 .ARM.attributes
                0x0000000000000000       0x35 framebuffer.o
 .ARM.attributes
                0x0000000000000035       0x21 framebufferstruct.o
 .ARM.attributes
                0x0000000000000056       0x35 GPIO.o
 .ARM.attributes
                0x000000000000008b       0x35 kernel.o
 .ARM.attributes
                0x00000000000000c0       0x35 mailbox.o
 .ARM.attributes
                0x00000000000000f5       0x21 main.o
 .ARM.attributes
                0x0000000000000116       0x35 math.o
 .ARM.attributes
                0x000000000000014b       0x35 memory.o
 .ARM.attributes
                0x0000000000000180       0x35 morse.o
 .ARM.attributes
                0x00000000000001b5       0x35 string.o
 .ARM.attributes
                0x00000000000001ea       0x35 time.o
nm

Code: Select all

000083f0 T abs
00008338 T __aeabi_idiv
00010000 D buffer
00030058 D CHARACTERS
00020000 D disp_size
00030000 D fb_info
00008048 T fb_init
00008018 t .free_to_enable_fpu
000081a8 T gpio_input
00008128 T gpio_output
000080dc T gpio_setup
000081d4 T kernelmain
00010000 d .LANCHOR0
00030058 d .LANCHOR0
00008838 r .LANCHOR1
00008044 t loop
00008328 T mailbox_ARM_to_VC
0000827c T mailbox_read
00008330 T mailbox_VC_to_ARM
000082d0 T mailbox_write
00008404 T memset
0000852c T morse_blink
00008620 T morse_code
00008670 T morse_code_blink
0000873c T morse_long
00008704 T morse_short
00008838 R MORSESYMBOLS
00008910 R NCHARS
000083fc T sign
00008814 T sleep
00008774 T strlen
00008804 T time
000087d4 T toLower
000087a4 T toUpper
This is main.s:

Code: Select all

.section .init

	ldr sp, =0x8000

mrc p15, 0, r0, c1, c1, 2            ;@ Read NSACR into R0
   cmp r0, #0x00000C00                  ;@ Access turned on or in AARCH32 mode and can not touch register or EL3 fault
   beq .free_to_enable_fpu
   orr r0, r0, #0x3<<10               ;@ Set access to both secure and non secure modes
   mcr p15, 0, r0, c1, c1, 2            ;@ Write NSACR
;@"================================================================"
;@ Bring fpu online
;@"================================================================"
.free_to_enable_fpu:
   mrc p15, 0, r0, c1, c0, #2            ;@ R0 = Access Control Register
   orr r0, #(0x300000 + 0xC00000)         ;@ Enable Single & Double Precision
   mcr p15,0,r0,c1,c0, #2               ;@ Access Control Register = R0
   mov r0, #0x40000000                  ;@ R0 = Enable VFP
   vmsr fpexc, r0                     ;@ FPEXC = R0
 ;@"================================================================"
;@ Enable L1 cache
;@"================================================================"
    mrc p15,0,r0,c1,c0,0               ;@ R0 = System Control Register

/*==========================================================================}
;{           RASPBERRY PI LEVEL L1 CACHE CONSTANTS DEFINED                }
;{=========================================================================*/
#define SCTLR_ENABLE_DATA_CACHE         0x4
#define SCTLR_ENABLE_BRANCH_PREDICTION   0x800
#define SCTLR_ENABLE_INSTRUCTION_CACHE  0x1000

    // Enable caches and branch prediction
    orr r0, #SCTLR_ENABLE_BRANCH_PREDICTION
    orr r0, #SCTLR_ENABLE_DATA_CACHE
    orr r0, #SCTLR_ENABLE_INSTRUCTION_CACHE

    mcr p15,0,r0,c1,c0,0               ;@ System Control Register = R0*/


	bl kernelmain

loop:
	b loop
My linker script:

Code: Select all

SECTIONS {
	.init 0x8000 : {
		*(.init)
	}
	
	.text : {
		*(.text)
	}

	.data : {
		*(.data)
	}
}

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

Re: Getting a framebuffer

Wed Jun 14, 2017 4:53 pm

You haven't got the CPU out of HYP mode it will crash the moment you touch those registers ... that is the problem

You can't do what you did above it is illegal, you will get an elevated level fault and you have no handler for that in the vector table.

http://infocenter.arm.com/help/index.js ... DAHFB.html
In HYP mode it has the ability to trap access of most system registers. The hypervisor decides what it wants to trap via special security registers the default setup by the bootloader is MANY :-)

Suggest you take the whole of the minimal boot.s and merge your stuff with it.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Thu Jun 15, 2017 9:56 am

I read somewhere that the processor had different modes but I didn't really understand it so I crossed my fingers that I wouldn't have to bother. Anyway, I copy and pasted the whole boot.s and replaced

Code: Select all

bl _cstartup
with

Code: Select all

bl kernelmain
but now kernelmain isn't even executed again.

Here is my code:

Code: Select all

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/*
* Authors: Camilo Talero
*
*
* File type: ARM Assembly
*
* This file contains assembly code needed to initialize the hardware of the
*Raspberry PI™ before execution of the main kernel loop
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.section .init
.global _start

_start:
        ldr     sp, =0x8000 // initialize stack pointer

/* CHANGES ADDED BY LdB */
        bl  RPi_CheckAndExitHypModeToSvcMode;   ;@ First check for HYP_MODE and if in it drop out to SRV_MODE

@"================================================================"
;@ PI NSACR regsister setup for access to floating point unit
;@ Cortex A-7 => Section 4.3.34. Non-Secure Access Control Register
;@ Cortex A-53 => Section 4.5.32. Non-Secure Access Control Register
;@"================================================================"
   mrc p15, 0, r0, c1, c1, 2            ;@ Read NSACR into R0
   cmp r0, #0x00000C00                  ;@ Access turned on or in AARCH32 mode and can not touch register or EL3 fault
   beq .free_to_enable_fpu
   orr r0, r0, #0x3<<10               ;@ Set access to both secure and non secure modes
   mcr p15, 0, r0, c1, c1, 2            ;@ Write NSACR
;@"================================================================"
;@ Bring fpu online
;@"================================================================"
.free_to_enable_fpu:
   mrc p15, 0, r0, c1, c0, #2            ;@ R0 = Access Control Register
   orr r0, #(0x300000 + 0xC00000)         ;@ Enable Single & Double Precision
   mcr p15,0,r0,c1,c0, #2               ;@ Access Control Register = R0
   mov r0, #0x40000000                  ;@ R0 = Enable VFP
   vmsr fpexc, r0                     ;@ FPEXC = R0
 ;@"================================================================"
;@ Enable L1 cache
;@"================================================================"
    mrc p15,0,r0,c1,c0,0               ;@ R0 = System Control Register

/*==========================================================================}
;{           RASPBERRY PI LEVEL L1 CACHE CONSTANTS DEFINED                }
;{=========================================================================*/
#define SCTLR_ENABLE_DATA_CACHE         0x4
#define SCTLR_ENABLE_BRANCH_PREDICTION   0x800
#define SCTLR_ENABLE_INSTRUCTION_CACHE  0x1000

    // Enable caches and branch prediction
    orr r0, #SCTLR_ENABLE_BRANCH_PREDICTION
    orr r0, #SCTLR_ENABLE_DATA_CACHE
    orr r0, #SCTLR_ENABLE_INSTRUCTION_CACHE

    mcr p15,0,r0,c1,c0,0               ;@ System Control Register = R0*/
 /* END OF CHANGES ADDED BY LdB */
    
    
    bl       kernelmain


 /* CODED ADDED BY LdB */
/* "PROVIDE C FUNCTION: bool RPi_CheckAndExitHypModeToSvcMode (void);" */
.section .text.RPi_CheckAndExitHypModeToSvcMode, "ax", %progbits
.balign   4
.type RPi_CheckAndExitHypModeToSvcMode, %function
.syntax unified
.arm
;@"================================================================"
;@ RPi_CheckAndExitHypModeToSvcMode -- Composite Pi1, Pi2 & Pi3 code
;@ Return: Drops out from HYP_MODE to SRV_MODE and FIQ/IRQ disabled
;@         If not in HYP_MODE will exit unchanged
;@"================================================================"
RPi_CheckAndExitHypModeToSvcMode:
   mrs r0, cpsr                     ;@ Fetch the cpsr register             
   and r1, r0, #0x1F                  ;@ Mask off the arm mode bits in register                            
    cmp r1, #0x1A                     ;@ check we are in HYP_MODE AKA register reads 1A                     
   beq .WeHaveHyperMode
   mov r0, #0;                        ;@ return false
   bx lr                           ;@ Return we are not in hypermode
.WeHaveHyperMode:
   bic r0, r0, #0x1F                  ;@ Clear the mode bits                   
   orr r0, r0, #0xD3                  ;@ We want SRV_MODE with IRQ/FIQ disabled         
   mov r1, #0                        ;@ Make sure CNTVOFF to 0 before exit HYP mode
   mcrr p15, #4, r1, r1, cr14            ;@ We do not want our clocks going fwd or backwards
   orr r0, r0, #0x100                  ;@ Set data abort mask    
   msr spsr_cxsf, r0                  ;@ Load our request into return status register
   mov r0, #1;                        ;@ return true
   /* I borrowed this trick from Ultibo because ARM6 code running on an ARM7/8 needs this opcode  */
   /* The ARM6 compiler does not know these instructions so it is a way to get needed opcode here */
    /* So our ARM6 code can drop an arm7 or arm8 out of HYP mode and run on an ARM7/8.             */
    /* Native ARM7/8 compilers already understand the OPCODE but do not mind it this way either      */        
   .long 0xE12EF30E                  ;@ "msr ELR_hyp, lr"
   .long 0xE160006E                  ;@ "eret"
;@ No ltorg data required for this function 
.size   RPi_CheckAndExitHypModeToSvcMode, .-RPi_CheckAndExitHypModeToSvcMode

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

Re: Getting a framebuffer

Thu Jun 15, 2017 4:13 pm

Ok couple of obvious problems and let me explain.

PROBLEM 1:
Key registers are not duplicated they exist independently for each security mode so they don't have to be saved down on the stack and the stack pointer happens to be one of those.

So lets follow the code

_start:
ldr sp, =0x8000 // initialize stack pointer .. This will be the stack pointer in HYP mode
bl RPi_CheckAndExitHypModeToSvcMode; ..... We drop from HYP_MODE to SRV_MODE

Do you see the problem the stack pointer in SRV_MODE it is not set
On the original code I do the SP again

ldr sp, =0x8000 // initialize stack pointer .. This will be the stack pointer in SRV_MODE

It isn't a duplication it is absolutely required and you left it out.

Now when you get into interrupts they also have there own stack pointers you have to set before you can use them. So the ARM is very different to say a microcontroller where you have only one stack pointer. The ARM has multiple stack pointers you need to get familiar with that.

PROBLEM 2:
Your linker directive has an obvious problem with my code. ... look at the section on my HYP to SRV_MODE
".section .text.RPi_CheckAndExitHypModeToSvcMode"

Your linker directive is
.text : {
*(.text)
}

See the problem all my sections are .text.xxxxxxxx and GCC will do the same at times. You need to change the directive to this, hopefully you see what it does (*.text.* is the key). I would also warn your data section also suffers a bit of same.
.text :
{
*(.text .text.* .gnu.linkonce.t.*)
}

That is why that function isn't mapping because it isn't being put in the elf file and the major reason for the code not working at the moment. So you know when it is fixed because you will see RPi_CheckAndExitHypModeToSvcMode in your map file.

PROBLEM 3:
This is not causing a problem but it will sometime from now and will drive you mad

You need to read up on .BSS for a C compiler
https://en.wikipedia.org/wiki/.bss
You currently have no .BSS defined in your linker file and you have left out the code that zeros it I gave. It is absolutely required for any C compiler to work properly. If you have zero init data and are relying on them to be zeroed it will be erratic without it.

I would add this after your data section in the linker directive and you should understand it now
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss .bss.* .gnu.linkonce.b.*)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
}

Hopefully you understand a bit more about linker files now. For linker files I would recommend
http://www.embedded.com/design/mcus-pro ... GNU-Part-3
You might recognize a few of the section descriptions I use from it :-)
If you look at the stack section in the link you might understand it now .. all those stack pointers.

Now some final housekeeping my kernelmain is exactly the same as your _cstartup it is simply a label where the code kicks into C. We just called it different names.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Fri Jun 16, 2017 6:25 pm

Oh! Thank you for that answer! I don't have my Raspberry PI at hand right now since I am using it for another project in parallell, so I'll try in a couple of days.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Tue Jun 20, 2017 12:05 pm

I have implemented the linker script as you said and added another stack pointer initialization and now kernelmain is called again but the framebuffer does still not work.

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

Re: Getting a framebuffer

Tue Jun 20, 2017 1:51 pm

You have reached the point I either need to see the code or you need to start with Makogan's code and slowly convert it to yours.

If you don't have a repo site just zip the code and put it on somewhere like dropcanvas.com and post the link.

Makogan
Posts: 71
Joined: Tue May 16, 2017 9:17 pm

Re: Getting a framebuffer

Tue Jun 20, 2017 8:12 pm

When you say it does not work, what do you mean? do you get a black screen or does the colorpalette rectangle enver go away?

Can you post only that section of the code you have for initializing the FB (the first message you send to the MB with the display dimensions and such)?

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Sun Jun 25, 2017 3:18 pm

I'm sorry for taking so long to answer.

When I say it does not work I mean that the colorpalette never goes away.

The code is available at http://dropcanvas.com/j4gu3.

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

Re: Getting a framebuffer

Mon Jun 26, 2017 8:13 am

You have no KEEP section in your linker file I am guessing your img file is empty. You boot code works correctly. You also have some problem with your mailbox code I haven't got time left tonight to fix but I have given you a way to do it.

Now I am going to give you the same advice that I gave Makogan override C system file names at your own peril !!!!!!!!!
Time.h, Math.h, String.h will already exist as system file on every C/C++ compiler on the planet and you are making a nightmare by trying to run your own files under those names.
Wikipedia has the list of C standard files and I strongly suggest you treat those as restricted names
https://en.wikipedia.org/wiki/C_standard_library

Now in this link I have given you a start for your code linked with my special smartstart bootloader.
http://dropcanvas.com/#0G4iv7F535kXZP
It is effectively invisible to all your code unless you specifically call it and it just adds 12K to the img most of which is the screen font. You do need to use my linker file which has some tricks like the stack it uses. What it allows you to do is debug to the screen :-)

Now I fixed your badly named "time" unit so it works correctly and used my internal Activity LED to show you that works. It's a little bit tricky because you can't access 64 bits in one go like you tried as it is illegal. The sample also puts a default message up to the screen so you can see how to run debug to screen. If you want to use my Pi3.bat file you will need to change the path to your compiler.

Long and short put kernel8-32.img on your SD card and you should see what it does.

Now you need to debug and fix your mailbox C code which isn't working but if you do it on that code you can print stuff to the screen to debug. I am not sure your loops will survive the optimizer they are relying on how the volatile is treated with the logical AND operator. I would suggest you dump the assembler and look at it :-)

You also need to read
viewtopic.php?t=165529&p=1068619
The status you need to check before a write to mailbox1 is offset 0x38 you are currently using mailbox0 at 0x18. I changed it but it didn't help on my system it still crashed me out and I am now out of time.

When you have it all working you can simply substitute your main.s file back for my smartstart.s in compilation.

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

Re: Getting a framebuffer

Mon Jun 26, 2017 2:46 pm

Had a client cancel appointment so had a few minutes to fix mailbox etc and put you back on your Main.S. I am not setup to do GPIO LED test so I added the PI3 activity LED on/off as well as GPIO. I got rid of a lot of maths from the GPIO so just check it still works.

I assume this is what you were trying to do .. puts a pretty pattern up on the screen and then loops blinking activity led and GPIO port
http://dropcanvas.com/#X790731ZjseRxG

Your img file drops back to 1Kb again as you don't have fonts and my print routines etc.

Now housekeeping:
I have set the resolution to my screen 1280x1024x32 I changed your fb_init to pass all 3 entries in
"FrameBuffer* buffer = fb_init(1280, 1024, 32);"

My screen wont lock at what you were using and it was easiest way to allow values to be change :-)

I would strongly suggest you get text up on screen as priority 1 as it makes debugging easier. I would also stay in 32 or 24 bit modes for now, as they are considerably easier than the other color modes.

gkraft
Posts: 41
Joined: Thu Sep 10, 2015 11:20 am

Re: Getting a framebuffer

Sat Jul 08, 2017 2:28 pm

Sorry for answering late. Thank you all so much for your help! We got a bit tired of getting stuck all the time so we have started another project instead, but all help was very appreciated and helpful. If we wish to continue with this project we will now be able to have a functioning framebuffer. Thank you!

Return to “Bare metal”

Who is online

Users browsing this forum: No registered users and 4 guests