Mmm (Memory Map Manipulator) perfect tool to (un?)break your SOC!

So i have this tool, where you can manipulate the registers of your SOC from your userpace. This is meant to be used by power users and most likely full of bugs but in past i leveraged this a lot when porting noname chinese tables to linux.

The idea is to mmap the SOC registers from user space and read and write to them. This tool additionally introduces a catalog approach where the target SOC’s memory registers are defined in a very simple format, and the tool calls for the registers for writing and reading.

i have ported rk3588 GPIO Core to and you can clearly see al the GPIOs as below. But it can be extended, with whatever CORE is available in the SOC say, vop2, dramctl, vpu, gpu, and my actual target pvtm.

So yeah here it is in case someone picks an interest.

Here are the external signals on GPIO4 pins ie (A0=0, and A1=1)

[alarm@alarm mmm]$ sudo python mmm.py get -c rk3588 -d GPIO4 -r EXT_PORT
-c rk3588 -d GPIO4 -r EXT_PORT -p A0 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p A1 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p A2 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p A3 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p A4 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p A5 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p A6 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p A7 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B0 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B1 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B2 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B3 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B4 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B5 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B6 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p B7 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C0 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C1 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C2 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C3 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C4 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C5 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C6 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p C7 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D0 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D1 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D2 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D3 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D4 = 1, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D5 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D6 = 0, (default=0)
-c rk3588 -d GPIO4 -r EXT_PORT -p D7 = 0, (default=0)

to start you can basically issue:

sudo python mmm.py get -c rk3588

WARNING: this tool can be very powerful, and as spiderman’s uncle said, it comes with big responsbilitiy. Ie: if you set a gpio to output true where it is phsically grounded without pull resistor, there is a certain risk that you might actually burn your socs GPIO output.

NOTE: to make it work you either need to pass iomem=relaxed to your kernel command line or you need to build your kernel with CONFIG_STRICT_DEVMEM=n CONFIG_IO_STRICT_DEVMEM=n options.

Edit: forgot to link the actual stuff :slight_smile:

1 Like

Thank you! After adding this to cmdline it looks like this:

root@rock-5b:/usr/local/src/mmm# python3 mmm.py get -c rk3588 | grep -i pvtm
-c rk3588 -d CORE_B0_PVTM -r VERSION -p reserved = 0, (default=0)
-c rk3588 -d CORE_B0_PVTM -r VERSION -p VERSION = 0, (default=515)
-c rk3588 -d CORE_B0_PVTM -r CON0 -p START = 0, (default=0)
-c rk3588 -d CORE_B0_PVTM -r CON0 -p OSC_EN = 0, (default=0)
-c rk3588 -d CORE_B0_PVTM -r CON0 -p OSC_SEL = 0, (default=0)
-c rk3588 -d CORE_B0_PVTM -r CON0 -p SEED_EN = 0, (default=0)
-c rk3588 -d CORE_B0_PVTM -r CON0 -p reserved = 0, (default=0)
-c rk3588 -d CORE_B0_PVTM -r CON0 -p WRITE_ENABLE = 0, (default=0)

Is this expected output or still something wrong? Also I saw the other PVTM candidates than big core 0 are commented. Why exactly?

Yeah i know PVTM not working so i commented them out, for some other PVTMS (ie: CORE_L) it even crashes the kernel on read so i commented them out.

My observation is for some memory areas, i presume kernel is still preventing to mmap or providing bogus 00 values. I also paced this issue with Allwinner SOC and DMC (memory contolelr) core. However they are readable when accessing from uboot command line (mainline). This can also be reproduced with devmem tool from busybox as well.

I implemented the GPIO core just to verify my approach is at least correct. Any ideas why bogus null values are there i would like to hear.

EDIT: https://github.com/radxa/kernel/blob/0a544b8c7f0c7eaad7c98498b9e18b5accfcff39/drivers/char/mem.c#L161
I am really suspecting this line, but i am notsure how code would even branch here, allowedvariable can only be 0 or 1 in arm64 according to here:
https://github.com/radxa/kernel/blob/0a544b8c7f0c7eaad7c98498b9e18b5accfcff39/arch/arm64/mm/mmap.c#L61.
May be i should attach a debugger somewhere to trace, but i think it is quite challenging to do it inside the kernel.

EDIT2: I think the only way to workaround this is just writing a dummy kernel module where it copies to physical memory to user space insecurely. I have a proof of concept and seems to be working. I will update later again.

@JonGroff Currently i have only added GPIO devices into rk3588 catalog, theoretically NPU would also work when implemented but please note that this tool can be notoriously slow if you are planning to interface it to some library for daily use. It is meant to be a hacking tool rather than user space driver toolkit.

@tkaiser For the PVTM iomem region providing all zero, i have written a kernel module called insecure_mem where all the security checks are bypassed but the result is still the same 00. This means that kernel itself would also not see PVTM regions. So i assume iomem region for PVTM is in a state that no values are valid for them. That part still needs investigation.

So i have spent quite a lot of time in this tool and it has opened a lot of new doors that was not possible previously.

Now it has a TUI. It has a great coverage of CRU / GRF regsiters of both CPU core and GPU.
Also can now clock gate a lot of frequencies and change the PowerDomains.

And that was the initial problem with accessing the PVTPLL registers, now they are wide open.
Now it is crystal clear how the PVTPLL works, edit, change and tune them.

Please note that for each given core, you need to enable to Power Domain of it, and activate the related clocks from CRU.

Here are some teaser what you can do with it.

My next target is to make the RK806 pmic completely unlocked so the device can be over or udnervolted in detail.

One interesting aspect of it, i think this is the only tool that exposes actual PVTPLL clock measurements first time ever. There is a hidden register that i could discover by reversing. And it seems this is not even available in neither open source or blob TFA (bl31). Now the device completely belongs to us.

Actual PVTPLL Cpu Core Clock

Modified GPU PVTPLL Ring Length to 1.1Ghz Gpu clock

Actual PVTPLL Gpu Clock

Detailed GPU clocks and muxes in between PLL and PVTPLL

EDIT: Here is a quick how to tutorial for GPU PVTPLL.

first make sure you set the gpu governor to userspace so that it wont interfere with the tool
first run the tool with sudo
then navigate rk3588->PMU->PV_DOMAINS->VD_GPU: and set to on

now the gpu is powered on, and we need to enable clocks

navigate to rk3588->CRU->GPU->CLKGATE_66->clk_gpu_all: and set to on

now all the clocks are also activated.
now we need to enable pvtpll

navigate to rk3588->GRF_GPU->GPU->PVTPLL_CON and set start=1, osc_en=1 ring_len=9 (you can tune this later on). and check the generated frequency from k3588->GRF_GPU->GPU->PVTPLL_STATUS.

and finally mux the gpu clock to PVTPLL from rk3588->CRU->clk_gpu_src_sel=PVTPLL

now the gpu is using the PVTPLL clocks where you can tune the ring len as you wish.

Please note that panthor driver does not really understand PVTPLL clocks. So i would suggest not using this when running a fully graphical environment when gpu is running and stopping. That would cause the system to freeze.

Process is similar for CPU, i hope this explains a little bit how to make use of the tool.

1 Like

@tkaiser i think you might really like with the new PVTPLL stuff.