5mattmatt1
Posts: 7
Joined: Sun Jan 13, 2019 10:12 pm

Rust framebuffer code

Mon Jan 14, 2019 1:07 am

I'm having the issue that my code works perfectly fine on QEMU, but I'm having some issues getting it to run on a physical raspberry pi 2. I know the framebuffer is being allocated on the raspberry pi because I get a black screen instead of the regular rainbow splash. The real issue is that I can't actually draw anything to the framebuffer. I'm sure its something about how QEMU implements the framebuffer, but I can't for the life of me find out what the difference between the two is. My first thoughts is that either the math I am using to draw a pixel is completely and utterly wonky, or I am not doing something right to convert the framebuffer pointer to a physical memory address.

Any help in figuring out what I'm doing wrong would be greatly appreciated. I am hosting all my code at: https://github.com/5mattmatt1/krust/tree/krust-arm

The relevant pieces are more than likely the function fb_initb in postman.rs and draw_char in font.rs.

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

Re: Rust framebuffer code

Mon Jan 14, 2019 1:12 pm

This is wrong you have wrong req size and alignment

Code: Select all

mail.mailbuffer[18] = 16; // Req. + value length (bytes)
 mail.mailbuffer[19] = 0; // Alignment = 16 
Your request length is 4 bytes you are simply providing the alignment aka one single u32 = 4 bytes
You say your want align 16 yet insert a value of zero ... yeah no

Try

Code: Select all

mail.mailbuffer[18] = 4; // Request data length provided (bytes)
 mail.mailbuffer[19] = 16; // Alignment = 16 
FYI you can also get the frame pitch at the same time by simply extending the message rather than another call next, they do play out in order.

5mattmatt1
Posts: 7
Joined: Sun Jan 13, 2019 10:12 pm

Re: Rust framebuffer code

Mon Jan 14, 2019 2:40 pm

I believe that was mostly just a case of not updating my comments to reflect changes made in my code (I have been tweaking the mailbox messages a lot). . Thank you for the tip, but I am aware of being able to throw them into one long array, I mostly wanted to keep it separate because I had some issues with throwing them into one long message when I was still creating everything like a giant struct. Plus when I split them up I can view their response codes separately and know if it the GPU is getting mad at my malformed get pitch message or at the allocating frame buffer message. If I can get a nice set of LED's set up on a breadboard hooked up to my GPIO pins I might just split up every different message and give it a different LED color in case the reason everything is messed up because I'm getting partial response error code because of one tag.

Sadly, even with your suggestions I am stuck with a sad black screen. Thank you though, I do appreciate your help immensely.

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

Re: Rust framebuffer code

Mon Jan 14, 2019 3:35 pm

First up print the framebuffer address returned (i see you have uart) and make sure it is something like 3fxx xxxx

Then simply make a rust equivalent of a u32 array from the framebuffer address of some whatever size and fire 0xFFFFFFFF at the array entries .. do you get anything on the screen ... you should have white line(s) at top of screen???

That is the basic start point and tells you if you have a valid framebuffer and you can ignore all the font stuff for that.

I probably should also warn you that you have selected 24bit pixel mode (3 bytes) which is the most problematic mode. Hopefully you realize the ARM can only do 32bit ,16 or 8 byte writes and so in that mode it must shift bits around. By far 32bit and 16bit pixel modes are the easiest because no bit manipulation is required you can just write a pixel.

Why I bring that up is this does not seem to reflect that .. I don't write rust but it looks wrong like it is doing 32bit mode is my guess.
If I can semi read rust it looks like pixel is a pointer to an array of u32 .. umm in 24bit mode it shouldn't it should be a byte pointer and you either write 3 bytes or do bit manipulation and do 16bit+8 bit write

Code: Select all

pub unsafe fn draw_pixel(addr: u32, x: u32, y: u32, pitch: u32, bit_depth: u32, color: u32)
{
    let pixel_offset: u32 = (x + (y * pitch)) * bit_depth;
    let pixel = (addr + pixel_offset) as *mut u32;
    *pixel = color;
}
With my limited rust to me that code smacks of each pixel being a u32 .. which it isn't in 24bit mode ???????

5mattmatt1
Posts: 7
Joined: Sun Jan 13, 2019 10:12 pm

Re: Rust framebuffer code

Mon Jan 14, 2019 4:53 pm

You are absolutely right about messing up with using 24 bpp. I have now swapped over to using 32 bpp.
As for the memory address, the value I get in QEMU is 0x3C100000.
I've tried the methods that I've seen in other's people's code such as:

Code: Select all

fb_ptr &= 0x3FFFFFFF;
as well as:

Code: Select all

fb_ptr |= 0x40000000;
fb_ptr &=!0xC0000000; // Rust insists on using ! for bitwise NOT instead of ~.
Neither of these gets it into that sweet coveted 0x3FXX_XXXX.
I'll start looking at other tricks to get those bits to be what I need them to be.

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

Re: Rust framebuffer code

Tue Jan 15, 2019 12:38 am

5mattmatt1 wrote:
Mon Jan 14, 2019 4:53 pm
As for the memory address, the value I get in QEMU is 0x3C100000.
That is the sort of address you should get .. what are you getting on the real hardware?

These next two lines are basically the same thing they correct a GPU address to ARM address either is correct
The GPU and the ARM share the same address bus but the same memory has different addresses to each
So you need one of them but not both.

Code: Select all

fb_ptr &= 0x3FFFFFFF;
fb_ptr &=!0xC0000000; // Rust insists on using ! for bitwise NOT instead of ~.
.
You do not need this next line below so get rid of it .... which is wrong because
1. It is for a Pi1
2. Is the reverse of above it turns a Pi1 ARM address to GPU

Code: Select all

fb_ptr |= 0x40000000;
.
However this brings up another error that may exist on early firmware for the Pi2 you may need to convert the ARM address of the structure when you send it ... I dont know how to write rust but on this line

Code: Select all

 us_mailbox_send(&mail.mailbuffer[0] as *const u32 as usize as u32,
                        PROPERTY_CHANNEL); 
.
We need it to send not the address "&mail.mailbuffer[0]" but that address OR'ed with 0xC000 0000 which converts that address to a GPU address on the Pi2 .. so is it &mail.mailbuffer[0] | 0xC0000000 ?????

I have one other concern which is the structure mail.mailbuffer aligned to 16bytes ... print the address &mail.mailbuffer[0] and check the bottom 4 bits are 0 telling us it is 16 byte aligned.

These sorts of problems may get thru QEMU where GPU is just emulated but they won't get thru the proper hardware.

5mattmatt1
Posts: 7
Joined: Sun Jan 13, 2019 10:12 pm

Re: Rust framebuffer code

Tue Jan 15, 2019 1:51 am

I have no idea what I'm getting on the real hardware. I've had some issues actually reading the output from TX that gets thrown into /dev/ttyUSB0. Stuff like screen and stuff like that just stay blank. I also tried just cat'ing /dev/ttyUSB0 and using tail -f but both of those don't show any output.

What you're saying about the memory addresses makes perfect sense, and you're mostly right about how you would OR the address of the mail buffer by 0xC000_0000. You would just do it as (&mail.mailbuffer[0] as *const u32 as usize) | 0xC000_0000. Rust is really particular about using references in a way similar to C++ as much as possible rather than raw pointers and even then, pointers are not effectively u32's that map out to somewhere in memory you have to cast them as usize or the compiler yells at you like no tomorrow.

I made the changes and pushed them up on github, but still looking at a solid black screen. I'll have to figure out if what I'm doing in UART is wrong or if I just am not reading it properly...

There shouldn't be any issues with aligning the mail buffer to 16. I have it wrapped up in a struct as the only member and that struct is aligned to 16 (I have no idea how to just align a u32 array to 16 in Rust). I double checked in QEMU and the memory address for both the struct and that struct's mail buffer's first element have the same memory address and that memory address has it's lower 4 bits as 0, so we should be good on that front.

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

Re: Rust framebuffer code

Tue Jan 15, 2019 2:05 pm

I actually have another concern now I look at your code in start.s

It appears to be setup for baremetal but your code in setup_stack will crash and burn at the moment as in it probably won't even display the coloured start screen.

The issue is simple in baremetal the Pi2 stub loader will give you the processor in hypervisor mode unlike what qemu probably does
Here is what the stub loader does
It is not valid to simply switch modes like the setup_stack does from hyp mode ... it is blatantly illegal

That is probably why you aren't even getting uart output as the processor has gone to security abort vector interrupt which is unset and probably junk :-)

In start.S try these assembler codes as the first thing executed

Code: Select all

_start:
mrs r0,cpsr
bic r0,r0,#0x1F
orr r0,r0,#0x13
msr spsr_cxsf,r0
add r0,pc,#4
msr ELR_hyp,r0
eret
/* lots of commented out code snipped */
bl setup_stack
.
The little bit of code drops the processor from hyp mode to service mode so you can then do the stack setups without crash and burn

5mattmatt1
Posts: 7
Joined: Sun Jan 13, 2019 10:12 pm

Re: Rust framebuffer code

Tue Jan 15, 2019 3:40 pm

I'm almost positive that's the key to what's going wrong. I've been having to cobble together an ARM assembly start.S from a few sources online, I suppose I should probably take the time to go through the main resources sticky and read through everything there is about ARM Assembly, otherwise I will just keep on blinding using code I only vaguely understand.

5mattmatt1
Posts: 7
Joined: Sun Jan 13, 2019 10:12 pm

Re: Rust framebuffer code

Wed Jan 16, 2019 2:39 am

I'm really annoyed with myself right now because I managed to get the UART to work on Raspberry Pi, but I didn't look at the output of the UART each iteration and just looked at the screen each time without thinking. Then suddenly I look back at the terminal and see:
&mail[0]: 0x000159B0
Get display size: Malformed Struct.
Setup framebuffer: Malformed Struct.
Get pitch: Malformed Struct.
0x00000010
0x00000010
I know that everything I was doing was a mixture of your:

Code: Select all

_start:
    mrs r0,cpsr
    bic r0,r0,#0x1F
    orr r0,r0,#0x13
    msr spsr_cxsf,r0
    add r0,pc,#4
    msr ELR_hyp,r0
    eret

    bl setup_stack

    bl main
and something that should look very familiar to you:

Code: Select all

_start:
    cpsid if

    /* Check if HYP mode */
    mrs r0, cpsr_all
    and r0, r0, #0x1F
    mov r8, #0x1A
    cmp r0, r8
    beq overHyped
    b continueBoot

overHyped: /* Get out of HYP mode */
    ldr r1, =continueBoot
    msr ELR_hyp, r1
    mrs r1, cpsr_all
    and r1, r1, #0x1f   ;@ CPSR_MODE_MASK
    orr r1, r1, #0x13   ;@ CPSR_MODE_SUPERVISOR
    msr SPSR_hyp, r1
    eret

continueBoot:
	bl setup_stack
	bl main
As well as tweaking the compiler settings on gcc and as to work for cortex-a7 instead of arm1176jzf-s.
I have no idea which combination I did to make everything work, but I swear I will find it.

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

Re: Rust framebuffer code

Wed Jan 16, 2019 1:50 pm

Spot the obvious error .. you supposedly OR'ed the address with 0xC000_0000 ... yet the value is 0x000159B0

Yeah not on this planet the value should be 0xC00159B0 .... Houston you have a problem with your rust code :-)

5mattmatt1
Posts: 7
Joined: Sun Jan 13, 2019 10:12 pm

Re: Rust framebuffer code

Wed Jan 16, 2019 2:16 pm

I did OR by 0xC000_0000 in one iteration of the code, but since I was focusing on seeing UART output and getting the assembly to get out of hypervisor mode working, I took it out like an idiot. The problem I'm having is that both of those sets of ARM instructions are either doing nothing at best or making it so that it never branches to setup stack and main, which is probably just a problem with me writing assembly and working that code into my current code.

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

Re: Rust framebuffer code

Wed Jan 16, 2019 3:12 pm

You are giving me a headache with your jumping all over the place who programs like that.

For dear life just follow the sequence and debug it as you go.
The first thing you code does is drop from hyp does stack setup and put a string out the uart ... I simply don't care for anything past that point and I would actually deadloop the processor at that point.

It's about 50 lines of assembler code and until it does that sequence who cares about everything else :-)
Once you have the uart up then move onto the rest.

Return to “Bare metal, Assembly language”