Okay. I have an idea. Let’s see what happens if we treat…
06: 00 B5 push {lr}
… as the start of this weird code(?) sequence. It pushes the link register (i.e., the return address to the caller).
08: 42 40 eors r2, r0
0a: 00 2A cmp r2, #0
This XORs R2 and R0 and compares the result against zero. But that’s just a decoy, as we’ll see.
0c: 00 F0 02 F8 bl #0x14
This calls into…
14: 70 46 mov r0, lr
16: 00 47 bx r0
… which moves the return address to R0, and then returns. Using the addresses in this disassembly (not in the actual boot ROM), the return address is 0x10; but LR and, therefore, R0 will actually contain 0x11 because the LSB signifies Thumb mode.
None of the previous three instructions modifies the flags. (I checked in the ARM reference manual.) Thus, “BHS” (branch unsigned higher or same) uses the flags from the “CMP R2,#0” above. _Every_ value of R2 is higher (in the unsigned sense) or same as 0. Hence, the following branch is always taken:
10: F6 D2 bhs #0
… to…
00: 11 38 subs r0, #0x11
R0 contained 0x11 relative to the start of this code sequence. (The absolute address in boot ROM is of course different.) Now, R0 points to the start of the code sequence.
02: C0 7A ldrb r0, [r0, #0xb]
This loads the byte at offset 0xB in this code sequence. Look above, it is 0x2A.
04: 00 BD pop {pc}
This returns to the caller, using the LR pushed at the beginning. The return value in R0 is 0x2A.
0x2A is 42 (decimal)! Could this be an Easter egg; a very obfuscated way of returning 42, the Answer to the Ultimate Question of Life, the Universe, and Everything? (Remember that the Raspberry design team is from Britain, same as Douglas Adams.)
Nice description of the correct intended behavior! It is indeed an Easter Egg; a function that returns the answer to the Ultimate Question of Life, the Universe, and Everything.
After the addition of double-precision floating point support in V2 of the boot ROM (B1 silicon), we had just over 30 bytes spare. Removing any of the slightly obtuse space-saving techniques already used in the code always resulted in code that didn't fit, so we were left with the free space.
Nature abhors a vacuum, so I decided on an Easter Egg (note there is no secure code in the RP2040 boot ROM). It was surprisingly challenging to come up with some very short code which actually did something, but whose purpose was not immediately obvious. I was also super interested to see how long it would take someone to find it - 15 months apparently :-)
Hopefully it provided you some amusement/puzzle value... I sort of hoped it would be more confusing the more ARM assembly you knew, as it potentially sets off all sorts of wrong pattern-matching in the brain.
This reads a bit like a spurious decompilation. It's sorta valid but doing very weird things. Random bytes will often decompile to valid Thumb that looks sort of right like this all the time.
04 pop {pc} -> this is an odd way to return from a function on ARM, and likely means that these first bytes would be a very odd function.
06 push {lr} -> OK, maybe a valid prologue, but this function ignores the result of the cmp and calls 0x14.
pop {..., pc} is THE standard way to return from a function that calls other functions itself, on Armv5 and above. Non tail functions usually do this: push {..., lr} ... pop {..., pc}
> As other people are saying, code seems to be jumped at at #6.
Well yeah, that's what I said above.
> LR is being clobbered by the blx
There's no blx in the first section. These first six bytes would only make sense if this small stub ended in bx lr, therefore I don't think it's a valid function.
Normally you'd save more than just PC as AAPCS (https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aap...) mandates stack to be aligned to 8 bytes for "public interface" functions. But this is is not a "public" function so it's fine to only save lr here.
"bx lr" is only used on it's own when the function doesn't call another function (altering lr), and doesn't need to save any registers.
If you see pop {lr}; bx lr then that's code that's being compiled to explicitly support Armv4 (e.g. Arm7TDMI)
God what a humorless crowd. We got a bug report from a customer on an Easter Egg once. There was nothing wrong with the software. It just annoyed them that there was an Easter egg.
The idea that Easter Eggs are security risks comes across as the most pedantic paranoid position. Statistically speaking software is not failing because of Easter eggs.
This does not seem to be about security but about typical American style “cover your ass” legalize thinking.
Sure if you create a space rocket control system I would not put in an Easter egg. But if it is a code editor, word processor, email reading client etc then who cares? Nobody will die and million dollar equipment is not going to blow up.
Disclaimer: I have never made an Easter Egg and I get that companies don’t do it if it causes problems with customers. I just think customers who complain about this should get a life.
I tend to agree with that sentiment. If most software "just worked", I would be okay with it from time to time. But it doesn't, so I am not. I feel the same with cutesy error messages. They're usually a bit condescending or infuriating when something is going wrong. I personally tend to be a bit clinical in my software development, despite the urge to be playful. I am also not a big fan of cutesy commit or issue descriptions either.
When I'm having problems with software I'm typically not in a whimsical mood. Most software I use are tools meant to help me do my job. A cutesy / playful error message coming from a misbehaving tool generates nothing but rage for me.
Cute, condescending error messages are unprofessional and unhelpful. If fewer programs were steaming piles of garbage I might feel differently about it.
It kind of looks like zphd is the label of the end of those bytes, right? I mean, that they are referred to somewhere else by using that as an end pointer.
That might be the case, but I wouldn't use Github search results to confirm this. I have no idea why, as this is super important, but code search in Github is surprisingly terrible. Not sure if this is just me or others have had similar experiences.
Not just you. It can give no results and partial results, which is sometimes fixed on a re-query.
But it also is just poor for code. I think it wants to find full words, so searching for substrings generally results in too few matches. That's made worse by its special character handling in word splitting and query parsing which makes some text impossible to find.
A trampoline in code is something you jump off of - essentially, a redirection snippet. You jump into it and it bounces you somewhere else.
In this case, the use is documented where it's implemented: https://github.com/raspberrypi/pico-bootrom/blob/master/boot... . It's a custom wrapper to call ROM functions. When the ROM function returns, the trampoline executes a debugger breakpoint. This is done so that the debugger can call into ROM easily without needing to set a hardware breakpoint.
if u go up it looks like there is a `debug_trampoline` function. so they are saying the `debug_trampoline_end` is a precompiled version of the `debug_trampoline` one. not sure if this is true or not
I am just interested not trying to argue, found this link.
https://wiki.segger.com/Raspberry_Pi_RP2040
The RP2040 includes a boot ROM which needs to be executed after reset in order to guarantee proper functionality. In case of a valid application has been detected in the external QSPI flash, the boot ROM copies the first 256 bytes from QSPI to SRAM5. In the RP2040 user manual, this code is called "flash second stage" (2nd stage bootloader) which is not part of the boot ROM but is part of the application image thus can be adapted by the user. The J-Link performs a device specific reset which halts on the first instruction at address 0x20041F00 of this so called "flash second stage" (bootloader).
The quoted description is correct. The boot ROM loads code from flash: the "second stage" loader. That loader then (usually) configures the RP2040 to execute the actual application directly from flash.
But the "Easter egg" function discussed in this HN thread is not inside any code loaded/executed from flash. It is inside the boot ROM (as I've repeatedly stated); and that is indeed read-only memory, i.e., it cannot be modified except by manufacturing a new chip revision.
Even if it's not obfuscated, what is this decompilation doing in the pico source repo? Are they claiming that is the real source code that someone wrote?
Looks like hand written assembly code to me. Also the legible function and label names indicate it was manually written. In diassemblies you usually have no such information.
I think you're right. This instruction is essentially redundant, since the following instruction also adds an offset - so I think it's very deliberate.
If I put myself in the shoes of someone truly malicious, I would request a backdoor in the chip implementation itself. Hardware is hard. Once you put it in the customer's hands they can't change much. Hidden opcodes or combinations/uses of legitimate opcodes that trigger undefined behaviors on the platform as a whole are the way to go. Firmware on the other hand can be patched or replaced.
It's probably an Easter egg or an undocumented workaround for something.
None of the previous three instructions modifies the flags. (I checked in the ARM reference manual.) Thus, “BHS” (branch unsigned higher or same) uses the flags from the “CMP R2,#0” above. _Every_ value of R2 is higher (in the unsigned sense) or same as 0. Hence, the following branch is always taken:
… to… R0 contained 0x11 relative to the start of this code sequence. (The absolute address in boot ROM is of course different.) Now, R0 points to the start of the code sequence. This loads the byte at offset 0xB in this code sequence. Look above, it is 0x2A. This returns to the caller, using the LR pushed at the beginning. The return value in R0 is 0x2A.0x2A is 42 (decimal)! Could this be an Easter egg; a very obfuscated way of returning 42, the Answer to the Ultimate Question of Life, the Universe, and Everything? (Remember that the Raspberry design team is from Britain, same as Douglas Adams.)