Firmware hacking / custom modding


As there still seem to be quite some issue’s and support here seems to be really slow/bad, I figured to see if it’s possible to do some homebrew development ourselves by modifying the firmware in the headset. This is a topic to share info and research about it.

So I’ve done some work already. First of all, we need a firmware to begin with :slight_smile: I couldn’t find any to download, here on the forum are some links to previous versions but they’re all down. But this is the topic, including instructions to flash the FW: Firmware Trouble! - #23 by Tomkin

So then I searched for references in the pimax directories to a .dfu file. I’ve found one in the log and it works, the FW can be downloaded here:

This BTW is newer than the version I’m currently running, I think this is a beta version. Anyway, I quickly found out that the firmware is unencrypted/unpacked, everything is in cleartext ! The FW is in the ‘dfu’ format, which is a propiatery format from “ST Microelectronics” and the file format is described here:

So it turns out there’s just 1 file in this image and for this particular image it starts at byte 0x125. It specifies a loading address of 0x8010000. On youtube there’s a video from someone who took the headset apart, it shows an ST microcontroller type SM32F, which is an 32 bits ARM microcontroller.

So, in short, you can cut out the first 0x124 bytes of the image, load it up in IDA pro, have it load at 0x8010000, specify ARM as architecture and it disassembles right away :slight_smile: It starts with a function table (each 4 bytes) referencing several functions and the code starts at 0x8010244

So that’s where I’m at now. I’d be surprised if there’s anyone here who is a reverse engineer/hacker like me that can help out (we’re a rare breed these days it seems) but I figured I’d start this topic anyway. I’ll dive into all this myself and will see if it’s possible to do some modding.

Oh btw, there are no signatures that prevent modification, which is awesome :slight_smile: There is a checksum though, as you can see in the file specification documentation I’ve posted earlier but that’s of course really easy to match.

BTW my first challenge would be to see if we can support 4k@30hz. It seems the headset garbles up when it receives 30 hz, but I think/hope this can be solved in FW.


Ok, some of the drivers included (you’ll see references in the code)

So this divides the code into sections to analyse. The whole layout of the image seems that the first part of the ROM contains pimax code and 2nd part are those drivers used by the pimax code to communicate with the hardware.

This USB HID code is compiled into the FW: stm32f429/00-STM32F429_LIBRARIES/usb_hid_device at main · MaJerle/stm32f429 · GitHub

1 Like

The version of the firmware you found is the current beta version (

Yes I figured so.

Anyway some more info, the 0x4XXXXXXX addresses are STM32 hardware mappings which can be found here:

Which shows for example: 0x40023C00 = flash memory interface.

1 Like

It seems that steam locks the output resolution to oculus and htc resolution.
I think that you will be limited by this fact in pimax mode.

1 Like

I don’t know if it’s accurate but according to the post below they are using the IGZO 4K LCD panel.

1 Like

For sure, this is for extended mode only.

1 Like

BTW I’m really not sure yet if my original goal is even feasible. I think the display always works at 60 hz. So there should be some kind of conversion going on from 30 hz input to 60 hz to the LCD. I think this might be really hard to add to the code via a FW mod without having any source code, but who knows, I’ll look into it. Basically what we’d need, the easy way, would be to send the same frame twice to the LCD. Better would of course be to have the headset interpolate the images but the easiest way would be to just duplicate each image to end up with 60 hz.

But this would also mean to first detect the frame rate and then convert if it’s 30 hz is detected. This seems quite an ambitious goal for a simple FW mod without any source code, but who knows …

1 Like

Anyway, some more info: those addresses starting with 0xE000 seem to be ARM specific registers, called “The System control block”:

And then we have those 0x2000XXXX addresses. These seem to be specific registers to store info regarding the state of several things, like if the system is in Pimax mode or not. So this seems to be regular RAM.

1 Like

BTW, this is the exact CPU version that’s inside our Pimax:

On that page tons of useful info.
For example:
page 51 contains a memory map

0x2000 000 - 0x2001 7FFF is indeed the 96 KB System SRAM

1 Like

Ure like ninja o.o

Awesome work !


The first bytes of the binary (after having removed the DFU info like explainded before), are the ‘vector table’. The layout is described here on page 39 of the Programming Manual:

1 Like

I’ve also found this thread on XDA, they’re reverse engineering another STM32 target and the thread contains a lot of very helpful info: LiveView reverse-engineering effort | Page 14 | XDA Forums

1 Like

Anyway, a small update on my project to get 4k@30 hz going: So as I’ve posted in the other hacker thread (wish I had created just one), the bulk of the LCD data that’s getting send to the LCD starts at 0x200008AC. Now I’ve been facing a huge mystery: the data gets read from that table and then written to the LCD over the I2C bus, but where is this data coming from ? This is a RAM location so it must be stored somewhere else and then copied to this location but I could not find a copy routine in the FW ! So I did some research on the internet and what I THINK is happening is that this part is part of the initialized ‘data’ section in the FW. This data is copied to RAM, maybe either by the bootloader or a linker created routine in the FW. The guy in that XDA thread, that I’ve just posted, did a simulation of his ARM binary and found the initialization data that way, with “Crossworks for ARM”, I’ve just downloaded it and am now waiting to receive my evaluation license.

Anyway if my theory is correct, I hope to find the init values at 0x200008AC via this simulation. Once I have those, I have the LCD data that’s being sent to the display to configure it. Hopefully this is somewhat standardized data and/or can be deduced easily. Next step would then be to modify it for 4k @ 30 hz, flash, run and PROFIT :slight_smile:

But who knows, it’s still a rocky road from here …


Its great work. Thank you. We hope that you will find needed solution to initialize 4k resolution

1 Like

Awesome Bro !!! I have a Champagne ready when your done LOL :grin:

1 Like

Thanks guys. Well I have some good news today, I’ve successfully taken the next step ! I received my CrossStudio demo license yesterday and started messing around it. I loaded the FW but it kept crashing once I tried executing it. Then I figured, maybe I need the bootloader too ! But wait, we don’t have the bootloader, it’s in our headset’s ROM area :slight_smile: Luckily I had already found some tools on the internet that can both read and write STM32 ROM & EEPROM, however the tool that looked most promising kept crashing after 49% of downloading the firmware region, it seemed it thought our FW was twice as big which made it crash once it broke the limits. So, I had to adapt that tool (luckily there was source code) and then I managed to dump the bootloader + our FW from ROM and EEPROM.

So, I then loaded that whole memory region into Cross studio and I could execute the bootloader and it didn’t crash anymore ! Then I did it again, changed the SP to the first initial vector value of our FW and set execution point to the entry point of our FW and it started executing ! Then I quickly found the routine that set the ‘initialized data’ region and I was right in my previous post: the whole region where the LCD data lies in RAM, is ‘initialized data’, that’s get set by some bootstrap routine, probably created by the linker !

In other words, I now have all the LCD commands that our FW sends to the LCD panel to configure it ! Yihaaa :slight_smile:

Now the next part might be the hardest part and also might be where I strand because this is all manufacturer specific data and it might simply be too hard do deduce/analyse. But I’m going to try and see if I can make sense out of the LCD data in the coming few days. This probably entails some internet research too, hopefully the LCD commands are pretty standardized, which would make it so much easier. If not, this might turn out a very hard nut to crack without getting data from the manufacturer…

We’ll see :slight_smile: Anyway, really happy with all the progress I’ve made so far !


woah great job!
whst’s your end goal after all this reverse engineering?

1 Like

Currently trying to get 4k natively going, at 30 hz, good for movie watching for example.

1 Like

What about 90hz 1080?
It would put this on par with current iteration of oculus and vive.
I’d still take 2k 60Hz over 1080 90Hz but having the option would be nice anyway

1 Like