f_ changed the topic of ##raspberrypi-internals to: The inner workings of the Raspberry Pi (Low level VPU/Hardware) -- for general queries about RPi please visit #raspberrypi -- open firmware: https://librerpi.github.io/ -- VC4 VPU Programmers Manual: https://github.com/hermanhermitage/videocoreiv/wiki -- don't ask to ask, just ask (and wait!) -- this channel is logged: https://libera.irclog.whitequark.org/~h~raspberrypi-internals
<dolphinana> Hi O/
dolphinana_ has joined ##raspberrypi-internals
<dolphinana_> Oof, I got disconnected suddenly but I'm back :)
dolphinana has quit [Ping timeout: 246 seconds]
dolphinana_ is now known as dolphinana
<dolphinana> I'm ready to be doing whatever I have to do to get the kernel Linux booting with librerpi >:D
<clever> dolphinana: :D
<dolphinana> Hi clever!
<clever> let me take a stab at something on my end....
<dolphinana> High five?
* dolphinana gives you a high five!
<clever> [nix-shell:~/apps/rpi/lk-overlay]$ make PROJECT=rpi1-test
<clever> first, i build rpi1-test
<dolphinana> Oh no, where's my micro-USB cable?
<dolphinana> Oh, it's on the floor :o
<dolphinana> By the way, I was kind of busy yesterday so I couldn't test the librerpi boot firmware yesterday. But now I'm here :)
<dolphinana> :)
<dolphinana> clever, are you still there? :)
<dolphinana> I'll be AFK for few minutes, brb
<clever> dolphinana: oh, got distracted, let me see....
<dolphinana> I'm back :)
<dolphinana> it's okay
<dolphinana> We won't be spending as much time as we did last time. It's midnight for me right now.
<dolphinana> So, we have about an hour to debug the firmware :)
<dolphinana> What was it? I think we were debugging that arm initialization stuff?
<dolphinana> I'll brb
<clever> keep getting distracted in another window
<clever> let me see
<clever> [nix-shell:~/apps/rpi/lk-overlay]$ qemu-system-arm -M help
<clever> Supported machines are:
<clever> raspi2 Raspberry Pi 2
<clever> hmmm
<clever> why is pi1 missing from this list?
<clever> let me find another version
<clever> raspi0 Raspberry Pi Zero (revision 1.2)
<clever> raspi1ap Raspberry Pi A+ (revision 1.1)
<clever> ah, thats better
<clever> -S freeze CPU at startup (use 'c' to start execution)
<clever> -s shorthand for -gdb tcp::1234
<clever> [clever@amd-nixos:~/apps/nixpkgs-master2]$ qemu/bin/qemu-system-arm -M raspi1ap -kernel ~/apps/rpi/lk-overlay/build-rpi1-test/lk.elf -S -s
<clever> dolphinana: with this, qemu should be running rpi1-test, its listening for gdb, and the cpu is paused immediately out of reset, so gdb can see everything....
<dolphinana> I'm back :)
<clever> xp /fmt addr -- physical memory dump starting at 'addr'
<dolphinana> Should I use qemu?
<clever> this is from `help` in the qemu monitor console (a tab in the gui)
<clever> i think i'll find the answer to the problem on this end, but you can follow along if you want to see how it all works
<clever> (qemu) xp /10i 0
<clever> 0x00000000: ea000006 b #0x20
<clever> 0x00000020: ee11cf10 mrc p15, #0, ip, c1, c0, #0
<clever> `xp /10i 0` tells qemu to dump from physical addr 0, print 10 opcodes, and to intrepret it as opcodes
<clever> the output matches up with `build-rpi1-test/lk.elf.lst`
<dolphinana> what does opcodes mean?
<clever> so that confirms, qemu loaded `build-rpi1-test/lk.elf` correctly
<clever> each line in assembly is 1 opcode
<dolphinana> I see, thanks :)
<dolphinana> I'm looking at `build-rpi1-test/lk.elf.lst` and it seems accurate to what qemu outputed
<clever> [nix-shell:~/apps/rpi/lk-overlay]$ gdb
<dolphinana> (btw, I'm not using qemu right now. I was talking about those qemu outputs that you sent)
<clever> (gdb) target remote localhost:1234
<dolphinana> why is the port number 1234?
<clever> (gdb) symbol-file build-rpi1-test/lk.elf
<clever> because `-s` to qemu is `shorthand for -gdb tcp::1234`
<dolphinana> I see
<clever> (gdb) stepi
<clever> 0x00000020 in bcm28xx_send_ipi (irq=<optimized out>, cpu_mask=0)
<clever> this tells gdb/qemu to advance by a single instruction
<clever> but the symbol it printed, oh, i know why
<clever> i think, double-checking
<clever> no, not that, but i can still debug without symbols
<clever> (gdb) set style enabled off
<clever> on my system, gdb is printing addresses in dark blue on black
<clever> and they are hard to read
<clever> this turns all colors off
<dolphinana> oh damn
<clever> (gdb) stepi
<clever> 0x00000024 in ?? ()
<clever> with stepi, i can advance one instruction at a time
<dolphinana> by the way, I tried running lk.elf in qemu and I see on the serial console that it's printing that string I wrote :D
<clever> nice
<clever> and does it crash the same way?
<dolphinana> It keeps spamming it...
<clever> sounds like its boot looping
<dolphinana> yeah, that was what I suspected
<dolphinana> anyway, you can move on :)
<clever> the symbols are somewhat broken in gdb, not sure why, but we can just manually handle that
<clever> if i open build-rpi1-test/lk.elf.lst
<clever> 00000df8 <uart_init>:
<clever> i can find the uart_init function
<clever> e5c: eafffd3e b 35c <unmask_interrupt>
<clever> and within it, the call to the unmask_interrupt function, where it first crashed
<clever> (gdb) break *0xe5c
<clever> Breakpoint 1 at 0xe5c
<clever> so i can just set a breakpoint there
<clever> (gdb) continue
<clever> Continuing.
<clever> Breakpoint 1, 0x00000e5c in ?? ()
<clever> (gdb)
<clever> and set it loose
<clever> and it automatically pauses, when it hits that line of code
<dolphinana> That 0xe5c. Is that an address in the code?
<clever> yep
<dolphinana> you set a breakpoint at 0xe5c so I suppose that's an address in the code
<dolphinana> Okay :)
<clever> e5c: eafffd3e b 35c <unmask_interrupt>
<dolphinana> I just wanted to double-check
<clever> its this line from my lk.elf.lst
<clever> yours will be different, based on changes youve made
<dolphinana> Looking for it
<clever> dolphinana: https://i.imgur.com/z2n3PvR.png
<dolphinana> Oh, I feel stupid :D
<dolphinana> I tried searching for it based on your qemu's output
<clever> oh, and another tip for gdb
<clever> if you hit enter without typing anything, it repeats the last command
<clever> so you can just keep hitting enter, to repeat stepi
<dolphinana> nice :)
<dolphinana> I'm not running gdb right now though
<dolphinana> I think I found unmask_interrupt "function"
<clever> you can see here, how i remembered that, and kept spamming enter, and how its advancing thru the code
<dolphinana> Do you use vim?
<clever> yep
<dolphinana> me too ;)
<dolphinana> btw, thanks for the tip about gdb
<clever> so now i basically just spam stepi, until the address deviates unexpectedly....
<clever> 0x00000454 in ?? ()
<clever> 0x000192d0 in ?? ()
<clever> like so!
<dolphinana> oh no
<clever> 454: eb00639d bl 192d0 <printf>
<clever> but in this case, it was expected
<dolphinana> printf
<clever> thats unmask_interrupt calling printf
<clever> 458: e3a00001 mov r0, #1
<dolphinana> Is it supposed to be calling printf?
<clever> in this case, i dont think printf is the problem
<clever> (gdb) print (char*)$r0
<clever> $2 = 0x1d194 "reg==0x%x, bit==%d\n"
<clever> this tells gdb, to cast r0 (printf's first arg) to a c string
<clever> printf("reg==0x%x, bit==%d\n", (uint32_t)reg, vector % 32);
<clever> because i have this in my copy, from when i was last debugging this issue
<dolphinana> you said cast? Does this have anything to do with pointers?
<clever> yeah
<clever> (gdb) print $r0
<clever> $1 = 119188
<clever> without the cast, gdb has no clue what the number means
<clever> because all the debug info (the elf) isnt loaded
<dolphinana> where's the debug info?
<clever> in the .elf file
<clever> but gdb is having trouble loading it
<clever> so i just didnt bother loading it
<clever> since i dont care about the printf, i went back to unmask_interrupt, and i can see 454 is where it calls printf, and 458 is right after printf has returned
<clever> (gdb) break *0x458
<clever> (gdb) cont
<clever> Breakpoint 2, 0x00000458 in ?? ()
<clever> so i can set a breakpoint right there, continue, and then go back so stepi'ing
<clever> reg==0x2000b214, bit==25
<clever> this also popped out on serial0
<dolphinana> stepi'ing sounds goofy :o
<clever> 468: eb00637c bl 19260 <puts>
<clever> 46c: eaffffdb b 3e0 <unmask_interrupt+0x84>
<clever> puts("unmasked")
<clever> the printf spam i added ages ago, when i had the same problem
<clever> (gdb) break *0x46c
<clever> Breakpoint 3, 0x0000046c in ?? ()
<clever> so ive skipped ahead again
<clever> 408: f1080080 cpsie i
<clever> and it hits this opcode, which i believe unmasks the irq
<dolphinana> What does "unmasking the irq" mean?
<dolphinana> and what does it mean when irq is masked?
<clever> while holding a spinlock, all irq's are masked (blocked)
<clever> so the code cant be interrupted by things
<dolphinana> so the opcode we're talking about now: all irq's would be unmasked (unblocked)?
<clever> yeah
<clever> (gdb) help stepi
<clever> Usage: stepi [N]
<clever> Argument N means step N times (or till program stops for another reason).
<clever> its not failing the smae way as hardware, so i'm going to try a more brute-force solution
<clever> (gdb) stepi 1000
<clever> 0x00000e98 in ?? ()
<clever> this will just run 1000 opcodes
<clever> and then i just keep doing that, until it boot-loops.....
<dolphinana> Can you pass 0xff as argument to stepi?
<dolphinana> I mean,
<dolphinana> Can you pass value in hexadecimal form?
<clever> probably
<dolphinana> Just a random thoughts in my head
<clever> 0x0001cbc8 in ?? ()
<clever> (gdb) stepi 10000
<clever> (gdb) stepi 10000
<clever> 0x0001b7cc in ?? ()
<clever> 0x000011cc in ?? ()
<clever> 1k was a bit slow, so i switched to 10k
<clever> cpu 0 data abort, synchronous external abort on read
<clever> DFAR 0x2040000c (fault address)
<clever> halting
<clever> DFSR 0x8 (fault status register)
<clever> and it then printed this in the serial0
<clever> so, lets assume 0x0001b7cc was it working "normally", and then 0x000011cc is after it failed
<clever> and it ran 10k opcodes in between those 2
<clever> 1b7cc is within __debug_stdio_write, that doesnt help much....
<clever> oh
<clever> starting app loader
<clever> but this is also the last thing it printed
<clever> so i can set a breakpoint there
<clever> loader_entry() then
<dolphinana> where's the "starting app loader" address
<clever> 00003234 <loader_entry>:
<clever> this address in the .lst file
<dolphinana> I see
<clever> app/linux-bootloader/loader.c here in the src
<dolphinana> I found it
<clever> (gdb) break *0x3234
<clever> oh, but i want to reset it all
<dolphinana> I found the function in app/linux-bootloader/loader.c :)
<clever> so i'll close qemu and gdb, and then restart/reconnect
<dolphinana> If I was the one running gdb, I would've entered `break *0x33a8` since the loader_entry function is at 0x000033a8
<clever> i did stepi 100, 6 times, and now its within arm_data_abort_handler
<clever> went too far!
<clever> so now i'll restart, and `stepi 500` this time
<dolphinana> do it
<dolphinana> what were you going to do now again?
<clever> loader_entry
<dolphinana> step into the loader_entry with gdb or...?
<clever> with gdb yeah
<dolphinana> I'll be AFK for few minutes, brb
<clever> oh, *doh*
<clever> printf("SCALER_DISPECTRL: 0x%x\n", *REG32(SCALER_DISPECTRL));
<clever> i had some 2d debug code in here, that i forgot to uncomment
<clever> so its been crashing in a different way
<clever> hmmm, its not looping for me
<clever> dolphinana: what does your log say in qemu when its looping?
<dolphinana> I'm back
<dolphinana> clever, let me see...
<dolphinana> Something like this:
<dolphinana> wait
<dolphinana> platform_irq:184: Hello kitty cat :3
<dolphinana> platform_irq:221: pend1 0x2
<dolphinana> platform_irq:240: cpu 0 vector 1
<dolphinana> Yeah, I wrote that part about kitty cat xd
<dolphinana> it was when we were debugging back in friday
<clever> ah, thats just the irq handler, working fully
<clever> there is probably a timer that is firing, causing it to irq every time
<clever> so qemu isnt failing the same way as real hardware
<dolphinana> how do we find the timer that's firing?
<clever> `pend1 0x2`
<clever> i think that is saying its timer irq 1
<dolphinana> is that a command? where do you run it?
<clever> its a quote from the logs you pasted
<dolphinana> oh
<dolphinana> lol okay nvm :D
<dolphinana> Oh yeah, I see it now
<clever> and i see, that is the default timer for arm
<clever> lk/kernel/timer.c LOCAL_TRACE would show more
<dolphinana> GLOBAL_DEFINES += VC4_TIMER_CHANNEL=1 ?
<dolphinana> that one?
<dolphinana> flip that LOCAL_TRACE to 1 >:3
<clever> that tells the timer driver, which channel to use
<clever> yeah
<clever> the rpi has a 64 counter, that counts up at 1mhz
<clever> the ST_CLO and ST_CHI registers, give the lower and upper 32bits of that count
<clever> then you have 4 compare registers, ST_C0 thru ST_C3
<clever> and when a compare register matches ST_CLO, it will fire one of the 4 timer interrupts
<dolphinana> wait... so...
<dolphinana> Can you tell me more about "the rpi has a 64 counter, that counts up at 1mhz" ?
<clever> there is just a 64bit number in the chip, that is counting up, 1 million times per second
<dolphinana> so after one seconds from the beginning, that 64bit number in the chip would've counted to 1 million?
<clever> yep
<dolphinana> wait, what's the maximum value that can be stored in 64 bit?
<clever> so if you want something to happen 0.5 seconds from now, you would get the current value of that counter, add 500k, then write that sum to a compare channel
<clever> > Math.pow(2,64)
<clever> 18446744073709552000
<clever> > Math.pow(2,64) / 1000000 / 3600 / 24 / 365
<clever> 584942.417355072
<dolphinana> that's a lot
<clever> about 584k years
<dolphinana> Okay, I guess I'll forget thinking about what would happen if it reaches the maximum value xD
<clever> only half forget :P
<clever> the compare registers are only 32bits
<dolphinana> pj
<dolphinana> oh
<clever> > Math.pow(2,32) / 1000000 / 3600
<clever> 1.193046471111111
<clever> it will wrap around every 1.19 hours
<dolphinana> oh
<dolphinana> umm, cool
<clever> and this is related to a bug ive had
<clever> the compare register defaulted to 0
<clever> and the irq's where enabled by default
<clever> 1 hour and 11 minutes after turning the pi on, the ST_CLO wrapped around to 0, and matched the compare register
<clever> causing an irq to fire
<clever> and that old code, wasnt able to handle interrupts
<dolphinana> Hey, I gotta go sleep soon, but we can do this for maybe 15 more minutes
<clever> i think i'm going to have to wire up jtag
<clever> qemu isnt able to reproduce the problem
<dolphinana> If you wire up the jtag, can you send me a picture?
<clever> i do have an old picture, on emin
<dolphinana> emin?
<clever> one min
<clever> the pi3 on the top is the target
<clever> the pi4 in the heatsink case is the debugger
<clever> with that, i can connect gdb directly to the cpu in the pi3
<clever> so i can debug it the same way as with qemu, but on real hardware
<dolphinana> man, my thoughts were silly. I thought you had to solder some wires to the bottom of the pi, but it seems like you don't? :P
<dolphinana> This seem a lot easier than I thought.
<clever> for the pi0-pi4, you can just expose the arm jtag on the gpio header
<clever> so you just need a compatible jtag adapter (or another pi), and you can debug it
<dolphinana> I think I have neither of these
<clever> do you have a second pi?
<dolphinana> no. Only that pi1
<clever> ah, that will be hard to debug then
<clever> but given the mess in my intc.c file, i had the same problem
<clever> so i just need to wire it all up, and see what happens
<dolphinana> Wait, what's so special about jtag that I need an additional hardware for that?
<clever> you need something that can speak jtag, that takes control of the rpi
<clever> oh, ftdi can also do it....
<dolphinana> ...
<dolphinana> how?
<clever> not sure yet
<clever> something in this
<dolphinana> I also have an Arduino UNO but I'm not sure if it can speak jtag.
<clever> arduino can, just need to program it with the right payload
<dolphinana> mmhmm..
<clever> oh, but is that 3.3v or 5v io?
<dolphinana> 5v io so I need to be careful
<dolphinana> umm...
<dolphinana> I know that GPIO on rpi operates at 3.3v
<clever> yeah
<clever> this mentions both the 5v issue, and also the ftdi option
<clever> ah, the official docs
<dolphinana> I'm looking at that FTDI chip. It says: FTDI 1760-C E6411501 FT232RL
<clever> yep, the classic 2232 based ftdi
<dolphinana> I think I really should go sleep now
<dolphinana> But thanks for the talk :)
<clever> yeah, i need to head to bed soon too
<clever> i'll try wiring jtag up tomorrow, and see what i can find
<dolphinana> that's good
<dolphinana> Good night
<dolphinana> and sleep well!
* dolphinana offers you a high five again!
<dolphinana> see ya :)
<clever> yep, goodnight
dolphinana has quit [Ping timeout: 255 seconds]
ckx has joined ##raspberrypi-internals
ckx has quit [Changing host]
ckx has joined ##raspberrypi-internals
srk_ has joined ##raspberrypi-internals
srk has quit [Ping timeout: 255 seconds]
srk_ is now known as srk
srk_ has joined ##raspberrypi-internals
srk has quit [Ping timeout: 255 seconds]
srk_ is now known as srk
dolphinana has joined ##raspberrypi-internals
jcea has joined ##raspberrypi-internals
jcea has quit [Quit: jcea]
jcea has joined ##raspberrypi-internals
<f_> clever: hi, have you wrote some more docs not on the website?
<f_> After I deployed it, that ia.
<f_> *is
<clever> f_: nothing in the docs repo you made
<f_> I mean in lk-overlay/docs and rpi-open-firmware/docs
<clever> ah, hmmm
<f_> So you didn't use the website repo at all :P
<f_> It's really easy to use by design, drop files in docs/ and it'll get rendered at librerpi.github.io
<clever> just some notes on how the 2d core works
<f_> I think at some point..should put some stuff on the website..
<clever> something ive been wanting to look into, is LaTeX and trying to make an official looking pdf
<f_> no markdown? :)
<clever> i want it to look like a real chip datasheet
<clever> with graphs and such
<f_> I can hack in support for latex tbh.
G33KatWork has joined ##raspberrypi-internals
<G33KatWork> heyho! you summoned me? ;)
<G33KatWork> I had to start my old irssi vm to join here...
<clever> G33KatWork: *waves*
<clever> G33KatWork: while i was waiting, i came up with a second way of dumping the RP1 boot rom
<G33KatWork> ohoo. how?
<clever> the i2c interface for bootstrapping, has both read and write routines
<G33KatWork> I tried reading, but couldn't make it work
<clever> the firmware only does 4 byte reads with it
<G33KatWork> I either to upcounting numbers or just 0xff
<clever> ah
<G33KatWork> I tried dumping the platform register to see if it works
<G33KatWork> in sysinfo
<clever> there is still the swd option then, one sec
<G33KatWork> can you paste your read code somewhere?
<clever> G33KatWork: https://i.imgur.com/9qa1CCU.png
<clever> this was found on the bottom of a pi2 board i believe
<clever> its the VPU jtag port
<clever> and youll find that on nearly every model of pi
<clever> 3, 4, 400, zeros
<G33KatWork> ahhh, nice. they labelled it on old chips
<clever> but the pi5, has 2 of those headers
<clever> somebody on the forums said there isnt enough pins wired up, and it may be SWD
<clever> i also discovered on the forums, that the debug uart (between the 2 hdmi) can be remuxed to cortex-a76 SWD
<clever> so you can debug the primary arm cluster via that debug header
<clever> let me get the i2c read/write code...
<G33KatWork> luke wren told stacksmashing (and he told me), that they are able to debug the RP1 over the PCIe link. it might have been altered along the way though and it's a misunderstanding
<G33KatWork> but maybe they really have something in hardware in BAR0 to do this
<clever> there are undocumented registers in the broadcom soc, that let you bit-bang jtag from the vpu
<clever> i can picture how the same may exist on the rp1
<clever> G33KatWork: https://gist.github.com/cleverca22/9f01bf27aeeb5c4a2c174bd5bf1449b0 this is what ive labeled up in ghidra
<G33KatWork> ha, they actually have routines in the videocore firmware to do this? I completely overlooked this...
<clever> its used by the code for bootstrapping the rp1
<clever> refresh the gist, added rp1_boot_load_firmware()
<clever> that has the exact pointer and size for the RP1 firmware payload
<clever> and the load addr
<G33KatWork> yes, that is what I found
<G33KatWork> and replicated
<clever> and entry-point
<clever> including entering at 0x141 from the start?
<G33KatWork> yeah
<clever> i assume you also found the armstub?
<clever> its based on https://github.com/ARM-software/arm-trusted-firmware and is much larger then before, which made finding it tricky
<G33KatWork> if you reset the RP1, the power LED turns orange because I guess the pin goes into high impedance. when I then try to reload it from linux, it stays that way
<clever> ah
<G33KatWork> then I wrote an endless spinning loop, loaded that, the i2c device vanished, so I knew that loading in theory worked
<clever> one guess i had, is that the bcm2712 end of the pcie link also has to be reset
<G33KatWork> and then I fought poking the right registers to turn on the LED I attached to GPIO17
<clever> i guess the next goal, would be to try and turn on the RP1 pl011 uart?
<G33KatWork> yeah
<G33KatWork> should be easy, clocking is an issue though
<clever> yeah, do you know the UUU trick?
<G33KatWork> for that we have the linux clock driver though. But I don't think it contains all the clocks
<G33KatWork> in the rp1 firmware is a lot of metadata structs about the clocking tree
<G33KatWork> haven't reversed that yet
<clever> yeah
<G33KatWork> what's the UUU trick?
<G33KatWork> autobauding?
<clever> U in binary, is just 0101_0101
<clever> plus the start and stop bits of uart, and it stays a perfect square wave
<G33KatWork> I can just hook up an oscilloscope and measure the resulting bit timing and based off the divider figure out the input clock. but yeah, that works
<clever> so you can just spit out U's endlessly, measure the frequency, half (or double?) that, and there is your baud
<clever> U just makes it simpler, because there is no cell that is 2 bits wide
<G33KatWork> right
<clever> i also have some asm that may help
<clever> this is part of my VPU entry-point
<clever> it configures the clock dividers and PL011 from scratch
<clever> so you can just steal the PL011 half
<G33KatWork> oh, tip how I found the RP1 firmware without reversing the videcore code: I used cpu_rec on the ELF and it found some aarch64 and armhf code
<clever> it also prints a U at the end to show signs of life, and give you something to trigger the scope on
<clever> ahh
<clever> ive not heard of cpu_rec before
<clever> looks handy, just need to deal with the compression first
<G33KatWork> the armhf code is the rp1 firmware. you need to go up a bit, because the vector table precedes the code, but you can spot the interrupt vectors all pointing to 0x20000000 and the initial stack pointer to somewhere in 0x10000000. that's the start
<G33KatWork> cpu_rec runs standalone and as a binwalk plugin
<G33KatWork> somebody recently reimplemted it in rust even
<G33KatWork> more perf
<clever> https://i.imgur.com/9Xa7gsN.png this is the start of my rp1.bin
<G33KatWork> yeah, that looks right
<clever> i labeled some of the vectors, from the arm docs
<clever> do you know if the mailbox execute code still works?
<G33KatWork> I wouldn't know where a mailbox is
<clever> the old VPU mailbox properties
<G33KatWork> oh, I haven't looked at that. only the RP1
<G33KatWork> the RP2040 has some fifo mailbox thing for inter-core comms in the SIO block. that doesn't seem to exist on the RP1
<clever> ive seen signs that the VPU is locked down far better now
<clever> but the binaries ive seen, also seem to lack signatures
<clever> how familiar are you with the boot chain on the VPU and its security?
<G33KatWork> how does that work with secure boot? do you need to sign everything including firmware with your own key?
<G33KatWork> I only know that they support secure boot, nothing more
<clever> pi0-pi400 all support hmac-sha1 signatures
<clever> a 20 byte key from the boot rom, gets XOR'd with a 16 byte key from OTP, to create a per-device key
<clever> (rpf then ignores this, and programs every device within a model with the same key)
<clever> that is then used to hmac-sha1 sign the first .bin stage
<clever> on pi0-pi3, verification was never enabled, but the OTP half of the key is still burned in
<clever> pi4 was the first model to enable the hmac check, but the early pi4 firmware didnt maintain the chain of trust
<G33KatWork> do they always check the hmac on booting or only when secure boot is provisioned?
<clever> pi4 always checks the hmac
<G33KatWork> meh
<clever> but the hmac isnt secure, i already dumped the key, and every device uses the same key
<G33KatWork> oh right, it's symmetric
<clever> the bcm2711C0 i believe added proper rsa signature support to the rom
<clever> there are 4 public keys baked into the rom, and they can never be changed
<clever> the .bin stage is then signed, with both the hmac and one rsa key
<clever> an OTP flag will switch it over to rsa verification instead
<G33KatWork> okay, so it can be made assymmetrical on request
<clever> and if the .bin stage detects that RSA checking is enabled, it will forcibly set SIGNED_BOOT=1 in the SPI config file
<clever> when SIGNED_BOOT=1 is set, there must be a pubkey.bin in the SPI, holding the user chosen rsa2048 key
<clever> and bootconf.txt + boot.img must be sigend with that
<clever> to prevent keychange attacks, the sha256 of pubkey.bin is burned into the OTP, and verified if RSA sigs are enabled
<clever> so, you have 3 levels of security
<clever> 1: the default, just hmac
<clever> 2: set SIGNED_BOOT=1 in the spi config, include a key, and sign bootconf.txt + boot.img
<clever> 2 can be undone at any time, by just re-flashing the SPI to remove it
<clever> 3: burn the pubkey.bin hash to OTP and enable RSA sigs
<clever> that key is now permanent, and you can never turn sig-checks off again
<G33KatWork> right, so you'd need a code executing bug to get past this
<clever> part of the support code for this, is that every compressed file in the SPI flash, has a sh255 footer, and the expected hash is baked into the bootcode.bin
<clever> those hashes are checked, even when not doing secure-boot
<clever> so if you try to modify bootmain.elf, then bootcode.bin will detect a corrupt hash and refuse
<clever> and if you fix the hash in bootcode.bin, a pi4 will just not execute the .bin
<G33KatWork> does the pi4 still execute bootcode.bin? I thought all of this is in the SPI eeprom
<clever> this will parse a pi4 .bin and tell you what the signatures state
<clever> internally, the 1st file in SPI is still refered to as bootcode.bin
<G33KatWork> oh, okay
<clever> there is a routine for opening SPI files by name, and an if statement maps bootcode.bin to the right magic#
<G33KatWork> and THAT in turn loads the later in the image?
<G33KatWork> *later ELF
<clever> yep
<G33KatWork> got it
<clever> let me find the graphs...
<clever> this would be every path you can go down while booting a vc4 (pi0-pi3) device
<clever> the boot rom supports booting from 8 different sources, detailed in this file
<clever> any of those sources, can contain a stage1 .bin file
<clever> and you then have 3 choices over which .bin you use
<clever> the signature code expects a bootsig.bin when on fat32 based sources
<clever> i'm not sure how spi/nand expect a signature
<clever> the other fun trick, is that the pi3 usb-host code had a lot of stability bugs
<clever> and to fix that, they made a bypass mode, the bootcode.bin only method
<clever> if bootcode.bin loaded from an SD card, but cant find any other firmware, it tries usb-host modes (msd and tftp) next
<clever> and this works even on the pi1
<clever> G33KatWork: https://i.imgur.com/4m8YZIV.png this is then how the old pi4 firmware worked
<clever> they basically just made "bootcode.bin only mode" the default, by including it on SPI flash
<clever> and the closed bootcode.bin would then support booting from sd/usb/tftp/nvme
<clever> https://i.imgur.com/njSA9eJ.png then along came network install, and they couldnt fit https within the 128kb size limit
<clever> so they split stage1 in half
<clever> the new bootcode.bin just does lpddr4 init, and loads bootmain.elf from spi
<clever> bootmain.elf then does booting from sd/usb/tftp/nvme/https
<clever> and it looks like pi5 just deleted stage-2 from that graph, bootmain now handles stage-2's job
<clever> the problem, as far as dumping the boot rom....
<clever> start.elf and start4.elf do some undocumented thing, that causes the bootrom to drop off the bus
<clever> so if you boot linux under the official firmware, you cant see the bootrom, even when doing reads from the VPU
<clever> but, if you compile a custom start.elf or start4.elf, you can read the ROM just fine
<clever> there is no start5.elf, how do i get my foot in the door?
<G33KatWork> yeah, they increased the flash size to 2MiB, I think
<G33KatWork> glitching the writes to the lockout bits could work, but that's going to be annoying
<G33KatWork> I did this successfully in the tegra X1 (switch) and X2 in the past
<clever> oh, on that subject, i did find a security exploit in the bcm2835 rom
<clever> to verify the hmac signature, it just signs it again, and uses plain old memcmp() to compare the 2 signatures
<clever> the memcmp implementation, will return on the first non-matching byte....
<clever> so, instead of having to brute-force 2^(20*8) signatures, you only have to brute-force 20*256 signatures
<clever> then you can gain execute, and dump the per-device key
<G33KatWork> oh nice
<clever> just rotate the first byte of the signature thru the whole 0-255 range, one of them will take slightly longer to fail
<G33KatWork> how did you manage to perform the brute force? did you emulate an sd card?
<clever> repeat on each byte
<clever> ive not verified the exploit
<clever> i did a binary diff on the bcm2835 and bcm2836 rom's
<G33KatWork> okay
<clever> and the memcmp routine is about the only difference
<clever> i only found the exploit, because they already fixed it
<clever> G33KatWork: back to your load_firmware.py ... lets say you removed the watchdog bits, can you try reading from 0x4000_0000 using i2c?
<clever> i expect to see 0x2000_1927 as a potential reply
<G33KatWork> so, write SRAM, then read the platform ID?
<clever> writing sram should be optional
<G33KatWork> that's what I tried. I'll try again and don't do a repeated start
<clever> 2 functions i found, related to this
<clever> oh, and what is that poke on 122 doing?
<G33KatWork> huh, I was wondering as well
<G33KatWork> also the poke on address 0 in the firmware load routine seems weird
<clever> yeah
<clever> the rom will likely answer some of those questions
<G33KatWork> 0x40014000 is the reset block
<clever> yeah
<clever> which is undocumented
<G33KatWork> a write at offset 0x3000 clears bits
<G33KatWork> so they are clearing some reset bit
<G33KatWork> that might explain why I couldn't read
<clever> yeah
<G33KatWork> let me boot the pi and try a few things
<clever> my pi5 still hasnt shipped
<clever> so ive been doing everything purely from the .bin files
<G33KatWork> I was just lucky to know somebody who was in cambridge
<G33KatWork> and then I got nerd sniped and tried things all weekend long while neglecting everything else :D
<clever> heh
<clever> on the signature side again (a bit), the pi4 stage1 files, all have "random" 20 bytes of garbage at the tail end
<clever> that is the hmac-sha1 signature
<G33KatWork> but now we are in a place where we could write some code to try and figure out which interrupt vectors and reset bits are for which peripheral and so on
<clever> but the pi5 .bin files, differ in other places, but end in the same byte sequence
<clever> implying its at least not signed the same way
<clever> oh, and maybe some of these pokes, are required to enable some block, before you run the stock rp1.bin
<G33KatWork> possible
<G33KatWork> yep
<G33KatWork> you need the reset poke
<clever> aha!
<clever> and maybe now you can run the stock rp1.bin as well?
<G33KatWork> otherwise I get 0s
<clever> G33KatWork: what about reading other things, can i2c now read the rom?
<G33KatWork> original firmware is still very red
<G33KatWork> and my blinky doesn't work. I think I am missing a reset as well
<G33KatWork> I'm going to try...
<G33KatWork> might just clear all the resets while I'm at it
<clever> oh, and another thing, when you hit the watchdog register, it likely resets everything again
<clever> and then the payload had to un-reset things
<G33KatWork> It's cumbersome to try things as I am losing ethernet all the time
<clever> yeah
<clever> are you familair with ppp?
<G33KatWork> yeah, could work
<G33KatWork> or just xmodem
<clever> oh, wifi?
<clever> the wifi is into the soc i believe
<G33KatWork> oh right
<clever> and to reduce the fallout from killing the rp1, a dtoverlay could just disable the whole thing?
<clever> maybe target the main rp1: node, so pcie is still there, and shows hotplug events
<G33KatWork> I think the kernel drivers don't like detaching from devices during runtime right now
<G33KatWork> I saw some todo comments
<G33KatWork> and at least the adc driver causes a stack trace on unload
<clever> but if the whole rp1 node is disabled in DT, the drivers never attach in the first place
<G33KatWork> oh, yeah
<clever> so it will act like a pcie device lacking drivers
<G33KatWork> when loading it in config.txt
<G33KatWork> yeah, I could build a more convenient setup
<clever> do you have anything swd capable? another pi or pico?
<G33KatWork> I even have the pico probe
<G33KatWork> the uart cable fits nicely
<clever> i think the pico-probe can also do SWD over the same pins
<clever> which is perfect
<clever> oh right, but we want the rp1 header, not the a76 header
<clever> if you look at the bottom of the pi5, youll see an SMD near the usb port, and another near the camera ports
<clever> if you probe those with a volt meter, do you see any activity?
<clever> even just idle high would be a sign of life
<G33KatWork> Copyright (c) Raspberry Pi (Trading) ltd. 2021
<G33KatWork> gitrev:99b5cdcdbb7430e89aaa09f26ffd256b46bdba36
<G33KatWork> got the rom
<clever> nice!
<clever> can you fire me a copy?
<G33KatWork> sure, email?
<clever> yep, youve got my email already
<clever> i assume i2c can just read the whole rom, once youve hit that reset?
<G33KatWork> I just clear all presumed resets now
<G33KatWork> write_bytes(0x40017000, struct.pack("<I", 0xffffffff))
<G33KatWork> write_bytes(0x40017004, struct.pack("<I", 0xffffffff))
<clever> ah
<G33KatWork> aol_you_got_mail.wav
<clever> :D
<clever> and into ghidra it goes...
<G33KatWork> glhf
<G33KatWork> when clearing the resets, the blinky also works again
<clever> having trouble finding any code yet
<clever> lots of pointers, but no opcodes
<G33KatWork> the dump looks correct though
<clever> ah, i just disassembled a random part, and found something
<G33KatWork> cpu_rec finds armhf code at 0x400
<G33KatWork> and 0x8400
<clever> both of those are just an `orr.w` and a `b` opcode
<clever> they look like junk
<clever> but at 1ce, i have something that looks like a real function
<G33KatWork> arm vs thumb maybe?
<clever> i'm assuming thumb only
<G33KatWork> k, that's correct
<clever> oh, the watchdog
<clever> there should be code in here, that reads the watchdog regs, for the magic code
<G33KatWork> I find countless of functions
<G33KatWork> not sure where the reset vector is
<clever> yep, i see a bunch of XREF's in the wdog area
<G33KatWork> but I am also using IDA
<clever> let me label them using the rp2040....
<G33KatWork> the vector table contains good looking pointers to vectors, but initial SP and reset vector are both 0
<G33KatWork> 0x1D0 might be the entrypoint
<clever> possible
<G33KatWork> first thing it does is catching the second core
<clever> oh, is that what e00ff01c is doing?
<G33KatWork> E00FF01C is not documented in the cortex m3 docs. at least I didn't find it
<G33KatWork> but I assume it contains the core ID
<G33KatWork> have to eat something. be back later
<clever> kk
<clever> interesting, at 2c9c, i see a function that takes an int
<clever> and then validates the watchdog message
<clever> if the int is 0, it checks the pc/sp we know of
<clever> if the int is 1, it checks a different 2 registers!
<clever> we know 0x40154010 is the pc for the entrypoint
<clever> and 0x40154018 is the sp
<clever> but notice the gap? its a array of 2 pc's, then 2 sp's!
<clever> the function at 2c9c, just verifies that the magic is right, the pc is not 0, and the sp is 4 byte alignd
<clever> and it is ran, with that mystery number from E00FF01C!
<clever> the 2nd pc register, needs to be xor'd with 0x4ff8_3f2d
<clever> i think
<clever> 0x4ff8_3fad maybe
<clever> there are 2 diff values used
<clever> oh, and the i2c slave.....
<G33KatWork> oh, you might be able to start the two cores independently?
<clever> i dont see any way to sev manually yet
<clever> so you would need to supply 2 entry-points, and then reset it
<clever> and it will fire up both cores in parallel
<clever> but then based on that, you could load rp1.bin to the stock addr, append blinky to the end, and then try to run both?
<G33KatWork> there might also be a magic bit in some control register somewhere to issue events
<G33KatWork> in the end, the event is just a single line going into the cpu core
<clever> yeah
<clever> but until we get more docs, we wont know where
<clever> i tried searching for one of the i2c controllers (not sure where i2c slave is?) and i found a reference to the timers instead
<clever> at b38 is a function doing something in the timer block
<clever> b64 as well
<clever> 84a0 is a function dealing with resets
<clever> and now i'm sort of at the brute-force stage, just disassemble anything following a function!
<G33KatWork> at 0x8000 is another vector table
<G33KatWork> this one has 0x1D0 as the reset vector
<clever> and is that 30d0 part of the stack?
<G33KatWork> wait
<G33KatWork> it's mirrored
<G33KatWork> I think the ROM is just 32K in size and I dumped it twice
<G33KatWork> but why are the first 8 bytes 0?
<clever> reading from 0 may be special
<clever> a command address
<G33KatWork> yeah, initial SP is at 0x100030d0
<G33KatWork> that might be the case, yeah
<clever> i see the gitrev string at 33ac
<clever> and again at b3ac!
<G33KatWork> yup, it is mirrored
<clever> hex 0x8000 apart
<G33KatWork> the datasheet says 64K though
<clever> definitely repeating
<clever> it may be a 64kb window, in the axi routing controller
<clever> but then only a 32kb rom, and it ignores the top addr bit from axi
<G33KatWork> yeah
<clever> also, addr 4 is zero as well
<clever> despite the mirror having a sp
<clever> wait no, 0 is sp, 4 is pc
<G33KatWork> yes
<G33KatWork> the first 0 bytes are 0
<clever> and both are 0
<clever> 0x0 and 0x4 are reporting 0
<G33KatWork> *first 8, goddamnit
<clever> oh, you did say that
<clever> i misread it as 4
<clever> odd, the addr of spi8 is at 3300
<clever> yeah, starting at 32bc, is a table of 32bit ints
<clever> some are pointers to i2c and spi controllers
<clever> others, no clue yet
<clever> that table is referenced by the entrypoint
<clever> aha, thats a chunk of .data, which gets copied from rom->ram
<clever> 32bc to 33dc gets copied to 0x1000_2000
<clever> oh right, uarts
<clever> nope, no hits
<G33KatWork> 32bc to 33dc must be the .data section
<G33KatWork> 10002000 is the core local data sram
<clever> yeah
<clever> oh, weird
<clever> i see a `bl 0x80f48`
<clever> and f48 is a valid function
<clever> but i am also seeing a few fishy places, where ghidra is claiming invalid opcodes
<clever> taking a break, and heading to bed in a few hours, i'll resume more tomorrow
<G33KatWork> I also have to do something else. I'll hang around in this channel though
<G33KatWork> Maybe I'll find some time to write some code to figure out some reset bits
<clever> my main focus has been the VPU and open firmware
<clever> but i have also ran a custom kernel on the rp2040 before, with a full command prompt and such
<clever> in theory, that could also be ported to the RP1...
<juri_> clever: stay focused. don't be me. :)
<clever> juri_: heh
juri_ has quit [Ping timeout: 260 seconds]