Rockbox.org home
Downloads
Release release
Dev builds dev builds
Extras extras
themes themes
Documentation
Manual manual
Wiki wiki
Device Status device status
Support
Forums forums
Mailing lists mailing lists
IRC IRC
Development
Bugs bugs
Patches patches
Dev Guide dev guide
Search



Donate

Rockbox Technical Forums


Login with username, password and session length
Home Help Search Staff List Login Register
News:

Rockbox Ports are now being developed for various digital audio players!

+  Rockbox Technical Forums
|-+  Rockbox Development
| |-+  Starting Development and Compiling
| | |-+  Beginning steps in kernel disassembly and analysis
« previous next »
  • Print
Pages: [1] 2 3

Author Topic: Beginning steps in kernel disassembly and analysis  (Read 3998 times)

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Beginning steps in kernel disassembly and analysis
« on: June 13, 2021, 06:20:02 PM »
With respect to amachronic's post in the Eros Q/K thread about how to go about reverse engineering the X1000 linux kernel, I thought I might start a dedicated thread if I'm going to keep pursuing this. I'm pretty sure I will have lots of really basic/beginner questions, and should probably put them here rather than stay in that thread where they're probably off-topic. And besides, maybe they'll help somebody in the future anyway.

To be honest, I don't expect to fully complete this on my own, but I thought I might get the ball rolling, and see if we make any progress.

So far I've successfully pulled out the following files from the rockbox-bootloader-patched update file from the ErosQ/K wiki page H2-v13-patched.upt. I'm using this one only because that's the particular device I have.

Out of the .upt file (which, it turns out, is really just an ISO with a different file extension), I got:

Code: [Select]
VERSION.TXT
UPDATE.TXT
SYSTEM.UBI
UIMAGE.BIN
UBOOT.BIN
_GITIGNO

So far so good, right?

Then I extracted the UIMAGE.BIN file as recommended with binwalk -e and got:

Code: [Select]
[user@localhost erosq kernel]$ binwalk -e UIMAGE.BIN

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0xD30BDBEF, created: 2020-03-09 06:41:44, image size:
 2612785 bytes, Data Address: 0x80010000, Entry Point: 0x80419300, data CRC: 0xF4F43C27, OS: Linux, CPU: MIPS, image type: OS Kernel Image,
compression type: gzip, image name: "Linux-3.10.14"
64            0x40            gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)

[user@localhost erosq kernel]$

This spit out a 5.4 MiB file called "40" (which I suppose is the address it found it at). I imported this into Ghidra with the recommended MIPS LE 32-bit architecture and base address of 0x80010000. Ghidra seemed to like this fine, and took maybe 15-20 minutes to crunch through the file when I imported it. (my computer is old)

So my first sanity check question - it looks like there's a whole lot of what I think are no-ops before the first function, does this look right? I'll attach a couple screenshots to show what I'm getting. Am I on the right track?

* Screenshot from 2021-06-13 17-34-24.png (94.29 kB, 1689x898 - viewed 113 times.)

* Screenshot from 2021-06-13 17-34-58.png (130.75 kB, 1673x945 - viewed 104 times.)
« Last Edit: June 13, 2021, 09:02:20 PM by dconrad »
Logged

Offline amachronic

  • Developer
  • Member
  • *
  • Posts: 261
Re: Beginning steps in kernel disassembly and analysis
« Reply #1 on: June 13, 2021, 08:29:13 PM »
hmm. Looks like you have a u-boot image there as well, and this kernel isn't self-decompressing (u-boot is doing that instead). You can pull the kernel entry address out of the uImage header in this case...

Code: [Select]
/* xImage */
00000000  27 05 19 56 ee 20 85 b0  5d c5 14 1d 00 33 b0 00  |'..V. ..]....3..|
00000010  80 f0 00 00 80 f0 00 00  2a d2 2d 06 05 05 02 00  |........*.-.....|
          ^^ startup  ^^ and entry address here
00000020  4c 69 6e 75 78 2d 33 2e  31 30 2e 31 34 2d 73 76  |Linux-3.10.14-sv|
00000030  6e 32 39 36 00 00 00 00  00 00 00 00 00 00 00 00  |n296............|

Not too sure which is what. It should be obvious in your case because the entry address must be higher than the load address. The kernel entry is in arch/mips/kernel/head.S, fittingly called kernel_entry. It's assembly so you can verify you got it by comparing the instructions. The function you're looking at isn't it. Control will transfer to C code by jumping to start_kernel at the end of kernel_entry and that'll give you a known starting point.

To give you an idea of something you're looking for -- the goal is not to disassemble the entire kernel after all  ;) -- check out this file: arch/mips/xburst/soc-x1000/chip-x1000/halley2/common/board_base.c. There's a function in it called board_base_init(). That's a function you want to locate, because it's the only place you can find a reference to platform_devices_array. Most platform_data structs which driver probe() functions will reference, are pointed to by this array, and from the platform_data struct you can learn GPIOs, details of the LCD interface configuration, clock speeds, and other useful stuff. I2C devices will probably be registered by board_base_init too. But some stuff will be hardcoded willy-nilly in the drivers. (I guess for a kernel you never update, maintainability is not a problem...)

Since board_base_init is an initcall it can be located in a table. See init/main.c, look for the initcall_levels array. And then look at the initcall_level_names below it. You can easily find the names array because it references a unique string "postcore". Once you find that you can find do_initcall_level() and from that, find initcall_levels. The initcalls are set up in one big table and the first entry of initcall_levels will point at the first one. You can trawl through the init calls one by one until you locate board_base_init(). That may require identifying a few other functions first, but the payoff is worth it because some information simply can't be found any other way.

Some other random notes:
  • Try to identify BUG_ON() and WARN_ON() statements. They are macros so this requires a bit of digging in the Linux source to match it up with the binary, but they can give you exact file and line number information and the source files using those macros are unlikely to have been changed. Many Linux API functions can be discovered this way.
  • You can find many GPIOs by identifying gpio_request(). A lot of the gpiolib functions contain code like printk(..., __FUNC__), and you can identify most of them that way very easily.
  • If you have dmesg output from the OF kernel, you can try looking for interesting messages that pop up there and seeing what code prints them.
  • LCD code: kernel/arch/mips/xburst/soc-x1000/chip-x1000/halley2/common/lcd/lcd-truly_tft240240_2_e.c. See how the platform data points to useful things... you want to find stuff like that.
Look at my Shanling Q1 patch in gerrit for an idea of what kind of information you actually need to grab. I think most, if not all of the chips you're dealing with have decent datasheets so finding the GPIOs and LCD related stuff is the most important. I2C bus numbers are useful too, but then again, you can just brute force them if you really have to, as long as you know what chips are supposed to be there.
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #2 on: June 14, 2021, 10:06:46 PM »
Some small progress I think:

So if I understand correctly, the kernel entry address given by the uimage header (read out when I used binwalk) is 0x80419300, and I can use this to directly find the corresponding address in the kernel. If I go to that address, it seems to match up, more or less, with this line in the generic source. (see screenshot)

Or, more accurately, I think that line 185 lines up with address 0x80419340

Code: [Select]
PTR_ADDIU  t0, LONGSIZE
LONG_S  zero, (t0)
bne  t0, t1, 1b

LONG_S  a0, fw_arg0
LONG_S  a1, fw_arg1
LONG_S  a2, fw_arg2
LONG_S  a3, fw_arg3

MTC0  zero, CP0_CONTEXT
...
...
...
j  start_kernel

Code: [Select]
                             LAB_80419340                                    XREF[1]:     80419348(j) 
        80419340 04 00 08 25     addiu      t0,t0,0x4
        80419344 00 00 00 ad     sw         zero,0x0(t0)=>DAT_80580004
        80419348 fd ff 09 15     bne        t0,t1,LAB_80419340
        8041934c 00 00 00 00     _nop
        80419350 5a 80 01 3c     lui        at,0x805a
        80419354 20 23 24 ac     sw         a0,offset DAT_805a2320(at)         --> (matches up with LONG_S a0, fw_arg0)
        80419358 5a 80 01 3c     lui        at,0x805a
        8041935c 1c 23 25 ac     sw         a1,offset DAT_805a231c(at)          --> (matches up with LONG_S a1, fw_arg1)
        80419360 5a 80 01 3c     lui        at,0x805a
        80419364 18 23 26 ac     sw         a2,offset DAT_805a2318(at)          --> (etc.)
        80419368 5a 80 01 3c     lui        at,0x805a
        8041936c 14 23 27 ac     sw         a3,offset DAT_805a2314(at)          --> (etc.)
        80419370 00 20 80 40     mtc0       zero,Context,0x0
        ...
        ...
        ...
        804193a0 68 31 15 08     j          FUN_8054c5a0                                     undefined FUN_8054c5a0()

It also seems that the fact that the kernel was gzipped inside the .bin file is not an issue? Is that true?


Edit to add: I just realized this, and it should have probably been obvious: on the macro scale, there are two intermediary labels present in the disassembled code (addresses 0x8041932c and 0x80419340), which probably line up with labels "0:" (line 162) and "1:" (line 185), huh? So now I'm feeling pretty dang confident this is correct, and the fact that it lines up with the uimage header's stated entry address makes it seem like I have valid code on my hands!

* Screenshot from 2021-06-14 20-27-40.png (157.81 kB, 1022x947 - viewed 91 times.)
« Last Edit: June 14, 2021, 10:11:18 PM by dconrad »
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #3 on: June 14, 2021, 10:17:57 PM »
One thing that took me a minute to realize as well is that instructions like PTR_LA, PTR_ADDU, PTR_SUBU, LONG_S, etc. are just macros defined mostly in kernel/arch/mips/include/asm/asm.h
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #4 on: June 16, 2021, 10:15:27 PM »
Some real progress now!

Quote from: amachronic on June 13, 2021, 08:29:13 PM
To give you an idea of something you're looking for -- the goal is not to disassemble the entire kernel after all  ;) -- check out this file: arch/mips/xburst/soc-x1000/chip-x1000/halley2/common/board_base.c. There's a function in it called board_base_init(). That's a function you want to locate, because it's the only place you can find a reference to platform_devices_array. Most platform_data structs which driver probe() functions will reference, are pointed to by this array, and from the platform_data struct you can learn GPIOs, details of the LCD interface configuration, clock speeds, and other useful stuff. I2C devices will probably be registered by board_base_init too. But some stuff will be hardcoded willy-nilly in the drivers. (I guess for a kernel you never update, maintainability is not a problem...)

Since board_base_init is an initcall it can be located in a table. See init/main.c, look for the initcall_levels array. And then look at the initcall_level_names below it. You can easily find the names array because it references a unique string "postcore". Once you find that you can find do_initcall_level() and from that, find initcall_levels. The initcalls are set up in one big table and the first entry of initcall_levels will point at the first one. You can trawl through the init calls one by one until you locate board_base_init(). That may require identifying a few other functions first, but the payoff is worth it because some information simply can't be found any other way.

I'm working through your example here, and I've identified - with a fair amount of certainty - the following:

  • start_kernel()
  • pr_notice()
  • parse_args()
  • "postcore" string
  • initcall_level_names[]
  • do_initcall_level()
  • initcall_levels[]
  • initcallx_start[] (0 through 7)

It took me a minute to figure out that you can not only bookmark stuff, but rename everything so the things you discover can propagate through the code.

It also took a bit of studying, but I think I see how items are added to the __initcall0_start[] arrays - through some magical define sorcery that took me like an hour to stare at, they use the labels "early", "core", "postcore", "arch", "subsys", "fs", "device", and "late" to correspond to levels 0-7, and then add functions by calling, for example, core_initcall(octeon_no_pci_init); to add octeon_no_pci_init() to the list of functions to run in level 1. Am I on track? Or off base? Or do I get a penalty for mixing my metaphors?  :P

I still haven't identified board_base_init though...
Logged

Offline amachronic

  • Developer
  • Member
  • *
  • Posts: 261
Re: Beginning steps in kernel disassembly and analysis
« Reply #5 on: June 17, 2021, 05:23:45 AM »
you're on the right track. Another tip, I think I might've have discovered platform_device_add using this string: "%s.%d.auto". It's the only user of that string. platform_device_register is a small wrapper which calls platform_device_add, but it is hard to identify on its own. The latter function doesn't have many other callers though.

The chain of references should look something like this--
Code: [Select]
[initcall array] -> board_base_init() -> platform_device_register() -> platform_device_add()
knowing the two "ends" you just need to chase down the references and find board_base_init in the middle. BTW, the platform device array is an array of structs like struct { void* pdevice; void* pdata; int size; }. pdevice is a struct whose first member points to a name string so you can see what device you are dealing with, and pdata is a blob containing the useful info. And convieniently, size tells you how big the pdata struct is.
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #6 on: June 18, 2021, 11:13:46 PM »
Well, I'm not sure if I'm barking up the wrong tree or what. I thought I had located board_base_init(), but none of the data it links to seem to quite be right. A bunch of pointers to strings are there, but between them are all zeroes (see screenshots).

I may need to backtrack and try to find something else, but I've done a lot of aimless scrolling in the hopes I would stumble across something, but that's probably futile.

* thought this was board_base_init.png (72.95 kB, 791x916 - viewed 91 times.)

* platform_device_array not quite right.png (206.35 kB, 1709x936 - viewed 80 times.)
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #7 on: June 18, 2021, 11:18:30 PM »
One other thing I found that looks halfway interesting (see screenshot)

* also found this.png (117.27 kB, 1005x1005 - viewed 102 times.)
Logged

Offline amachronic

  • Developer
  • Member
  • *
  • Posts: 261
Re: Beginning steps in kernel disassembly and analysis
« Reply #8 on: June 19, 2021, 08:03:13 AM »
That's definitely the platform_devices_array at 80572854. Those extra references near the beginning that Ghidra adds are noise -- direct references that happen to occur from the loop. I guess its analysis is not very deep and it has a hard time understanding the difference between things added by the compiler to implement the loop guard condition vs. "genuine" data accesses... but whatever.

The pointers like PTR_s_gpio-keys_XXXX are pointing to struct platform_device instances, I think. That's a huge struct I believe, mainly members used at runtime, that's why there are so many zeros. But you should see the grey text like = 804b8c6c off to the side if there is any nonzero data inside which looks like an address, those addresses are clickable and you can follow the links in case they point to useful data or functions... I think there are tables of function pointers for driver ops. Maybe other things, I'm not sure.

DAT_80511180 for example should be one of the platform data blobs, in the case of jzmmc_v1.2 it will be struct jzmmc_platform_data. Cf. arch/mips/xburst/soc-x1000/chip-x1000/halley2/common/mmc.c. You should have another driver named something like jz-fb, and its platform data blob should define details of your LCD's interface. See struct jzfb_platform_data.

Go look at one of the other LCD drivers to get an idea of what you're looking for, mainly you want to figure out bpp, smart_config.bus_width, smart_config.write_gram_command, and smart_config.data_table. There are also the LCD ops for powering on the panel (GPIOs, levels, timings, etc. needed to power it up.)

FUN_805614c0 is most likely i2c_register_board_info. 1st argument is the bus number -- 0,1, or 2 corresponding to the same number bus on the X1000 -- and type of the 2nd argument is an array of struct i2c_board_info. That will contain at least your I2C device addresses, and possibly platform data blobs.

Another thing you can try is identifying gpiolib functions (drivers/gpio/gpiolib.c). Each function tends to have a WARN_ON statement or some other debug message which causes the functions to reference their own name. Most useful: gpiod_request and from there it is not hard to find the public API gpio_request. Often that is called with hardcoded GPIO numbers. And you can find the probe() functions of any drivers using a GPIO, since they all must call gpio_request before doing anything with the GPIO. gpio_direction_output/input are useful to find other driver functions. The GPIO numbering scheme is port*32 + pin. Ports are A = 0, B = 1, etc.

Those strings ldo0, ldo1, vdd_cpu... probably part of AXP192's axp_mfd driver. There's a copy of that driver in the M0 kernel sources (download links are on the Shanling Q1 wiki page). I did diassemble that driver quite a bit for the Q1, but I don't remember if I ever found the one voltage setting I needed to change in there, or if I just grabbed it from the running OF's sysfs. I think all I may have concluded from the diassembly was that the Q1 almost certainly had an AXP192, based on which #ifdef'd code appeared to be in the binary. There's a lot of data tables and boilerplate code, fairly straightforward but tedious to handle. Probably the interrupt line GPIO is the only easy-to-find thing.
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #9 on: June 19, 2021, 08:34:40 AM »
Oh, excellent! I was thinking it wasn't it due to how it didn't seem to rigorously follow the struct pattern of pointer to string, pointer to data, size, but I guess I just didn't quite understand what I was looking for (data sure looks different when you're looking directly at bits and bytes, I guess)

Thanks for the explanations, I'll start digging and see what details I can find!
Logged

Offline amachronic

  • Developer
  • Member
  • *
  • Posts: 261
Re: Beginning steps in kernel disassembly and analysis
« Reply #10 on: June 19, 2021, 09:44:54 AM »
Quote from: dconrad on June 19, 2021, 08:34:40 AM
it didn't seem to rigorously follow the struct pattern of pointer to string, pointer to data, size

It does :) you just made some of those "pointer to data" an int. And ghidra obscured the beginning of the array with "false" references.

Recommend you create a struct -- select the data members of one struct instance in the main window, press shift+[ -- clear the types from the entire range (select it & press C) and assign the whole thing to an array of structs. (You may have to clear spurious types added by ghidra near the end of the array since it won't let you cause an overlap with other typed data.)

I found it's good to create structs aggressively even if creating them by hand is a bit slow... it pays off later. And ghidra also lets you use bitfields in structs, which is sometimes necessary. (bitfield type is named like uint:N). Should you need to amend the struct due to wrong members, wrong alignment, etc, you can quickly edit it and any place the struct is used will automatically update to the new definition. Very handy.
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #11 on: June 19, 2021, 06:18:47 PM »
Quote from: amachronic on June 19, 2021, 08:03:13 AM
Go look at one of the other LCD drivers to get an idea of what you're looking for, mainly you want to figure out bpp, smart_config.bus_width, smart_config.write_gram_command, and smart_config.data_table. There are also the LCD ops for powering on the panel (GPIOs, levels, timings, etc. needed to power it up.)

Some progress on the LCD structs, though I'm having trouble figuring out jzfb_platform_data - nothing in it seems to line up quite right, even if I get creative with padding in between stuff. fb_videomode seemed to go together pretty smoothly though. This is pointed to from the pdata position.

Code: [Select]
                             jzfb_platform_data                              XREF[1]:     805728e8(*) 
        80514788 01 00 00 00     uint       1h
        8051478c 14 48 51 80     addr       fb_videomode                                     =
        80514790 00              ??         00h
        80514791 00              ??         00h
        80514792 00              ??         00h
        80514793 00              ??         00h
        80514794 0d              ??         0Dh
        80514795 00              ??         00h
        80514796 00              ??         00h
        80514797 80              ??         80h
        80514798 18              ??         18h
        80514799 00              ??         00h
        8051479a 00              ??         00h
        8051479b 00              ??         00h
        8051479c 1f              ??         1Fh
        8051479d 00              ??         00h
        8051479e 00              ??         00h
        8051479f 00              ??         00h
        805147a0 1f              ??         1Fh
        805147a1 00              ??         00h
        805147a2 00              ??         00h
        805147a3 00              ??         00h
        805147a4 00              ??         00h
        805147a5 00              ??         00h
        805147a6 00              ??         00h
        805147a7 00              ??         00h
        805147a8 00              ??         00h
        805147a9 00              ??         00h
        805147aa 00              ??         00h
        805147ab 00              ??         00h
        805147ac 11              ??         11h
        805147ad 00              ??         00h
        805147ae 00              ??         00h
        805147af 00              ??         00h
        805147b0 01              ??         01h
        805147b1 00              ??         00h
        805147b2 00              ??         00h
        805147b3 00              ??         00h
        805147b4 4c 48 51 80     addr       fb_videomode.flag                                = null
        805147b8 08              ??         08h
        805147b9 00              ??         00h
        805147ba 00              ??         00h
        805147bb 00              ??         00h
        805147bc 00              ??         00h
        805147bd 00              ??         00h
        805147be 00              ??         00h
        805147bf 00              ??         00h
        805147c0 38              ??         38h    8
        805147c1 00              ??         00h
        805147c2 00              ??         00h
        805147c3 00              ??         00h
        805147c4 7c 48 51 80     addr       LAB_8051487c
        805147c8 00              ??         00h
        805147c9 00              ??         00h
        805147ca 00              ??         00h
        805147cb 00              ??         00h
        805147cc 00              ??         00h
        805147cd 00              ??         00h
        805147ce 00              ??         00h
        805147cf 00              ??         00h
        805147d0 00              ??         00h
        805147d1 00              ??         00h
        805147d2 00              ??         00h
        805147d3 00              ??         00h
        805147d4 00              ??         00h
        805147d5 00              ??         00h
        805147d6 00              ??         00h
        805147d7 00              ??         00h
        805147d8 00              ??         00h
        805147d9 00              ??         00h
        805147da 00              ??         00h
        805147db 00              ??         00h
        805147dc 00              ??         00h
        805147dd 00              ??         00h
        805147de 00              ??         00h
        805147df 00              ??         00h
        805147e0 00              ??         00h
        805147e1 00              ??         00h
        805147e2 00              ??         00h
        805147e3 00              ??         00h
        805147e4 00              ??         00h
        805147e5 00              ??         00h
        805147e6 00              ??         00h
        805147e7 00              ??         00h
        805147e8 00              ??         00h
        805147e9 00              ??         00h
        805147ea 00              ??         00h
        805147eb 00              ??         00h
        805147ec 00              ??         00h
        805147ed 00              ??         00h
        805147ee 00              ??         00h
        805147ef 00              ??         00h
        805147f0 a8 94 01 80     addr       LAB_800194a8
        805147f4 d4 93 01 80     addr       FUN_800193d4
        805147f8 00              ??         00h
        805147f9 00              ??         00h
        805147fa 00              ??         00h
        805147fb 00              ??         00h
        805147fc 00              ??         00h
        805147fd 00              ??         00h
        805147fe 00              ??         00h
        805147ff 00              ??         00h
        80514800 00              ??         00h
        80514801 00              ??         00h
        80514802 00              ??         00h
        80514803 00              ??         00h
        80514804 00              ??         00h
        80514805 00              ??         00h
        80514806 00              ??         00h
        80514807 00              ??         00h
        80514808 00              ??         00h
        80514809 00              ??         00h
        8051480a 00              ??         00h
        8051480b 00              ??         00h
        8051480c 00              ??         00h
        8051480d 00              ??         00h
        8051480e 00              ??         00h
        8051480f 00              ??         00h
        80514810 00              ??         00h
        80514811 00              ??         00h
        80514812 00              ??         00h
        80514813 00              ??         00h
                             fb_videomode.flag                               XREF[1,1]:   8051478c(*), 805147b4(*) 
                             fb_videomode
        80514814 e0 8d 4b        fb_video
                 80 50 00
                 00 00 40
           80514814 e0 8d 4b 80     addr      s_320x240_804b8de0      name          = "320x240"         XREF[1]:     8051478c(*) 
           80514818 50 00 00 00     uint      50h                     refresh
           8051481c 40 01 00 00     uint      140h                    xres
           80514820 f0 00 00 00     uint      F0h                     yres
           80514824 50 c3 00 00     uint      C350h                   init_pixclock
           80514828 00 00 00 00     uint      0h                      pixclock
           8051482c 00 00 00 00     uint      0h                      left_margin
           80514830 00 00 00 00     uint      0h                      right_margin
           80514834 00 00 00 00     uint      0h                      upper_margin
           80514838 00 00 00 00     uint      0h                      lower_margin
           8051483c 00 00 00 00     uint      0h                      hsync_len
           80514840 03 00 00 00     uint      3h                      vsync_len
           80514844 00 00 00 00     uint      0h                      sync
           80514848 00 00 00 00     uint      0h                      vmode
           8051484c 2c 2c 2c 2c     uint      2C2C2C2Ch               flag                              XREF[1]:     805147b4(*) 

I had some progress on jzmmc_platform_data, too, but again I can't quite get stuff to line up correctly. I think the mmc_recovery_info struct is located directly below it, but it doesn't seem to fit before the pointer to s_bt_power_804b761c.

Code: [Select]
                             jzmmc_platform_data_80511180                    XREF[1]:     8057287c(*) 
        80511180 02 00 00        jzmmc_pl
                 00 00 00
                 30 00 07
           80511180 02 00           ushort    2h                      removal                           XREF[1]:     8057287c(*) 
           80511182 00 00           ushort    0h                      sdio_clk
           80511184 00 00 30 00     uint      300000h                 ocr_avail
           80511188 07 00 00 00     uint      7h                      capacity
           8051118c 00 00 00 00     uint      0h                      pm_flags
           80511190 00 6c dc 02     uint      2DC6C00h                max_freq
           80511194 00 00 00 00     int       0h                      UNDEFINED
           80511198 b0 11 51 80 00  addr      PTR_805111b0            *recovery_info = NaP
                    00 00 00
           805111a0 00 00 00 00 00  addr      00000000                *gpio
                    00 00 00
           805111a8 00 00 00 00     uint      0h                      pio_mode
           805111ac 00 00 00 00     int       0h                      (*private_in
                             PTR_805111b0                                    XREF[1]:     80511198(*) 
        805111b0 ff ff ff        addr *     NaP
                 ff 2b 00
                 00 00
                             partition_num
        805111b8 2a 00 01 00     uint       1002Ah
                             permission
        805111bc ff ff ff ff     uint       FFFFFFFFh
                             protect_boundary                                XREF[1]:     80572884(*) 
        805111c0 1c 76 4b 80     uint *     s_bt_power_804b761c                              = "bt_power"
        805111c4 ff ff ff ff     int        FFFFFFFFh
        805111c8 00              ??         00h
        805111c9 00              ??         00h

I'm going to just keep inspecting different stuff, there's a lot to go through!
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #12 on: June 19, 2021, 10:38:06 PM »
I have a suspicion that the jzfb_platform_data struct is actually the one outlined in arch/mips/xburst/soc-x1000/include/mach/jzfb.h, could this be true?
Logged

Offline dconrad

  • Developer
  • Member
  • *
  • Posts: 122
Re: Beginning steps in kernel disassembly and analysis
« Reply #13 on: June 19, 2021, 11:45:13 PM »
I'm going out on a limb here, but I found 2 LCD jzfb_platform_data structs that seem to match up somewhat with the data I have, though I can't get the struct to line up right (it uses bitfields...), so I'm probably in error here...

lcd-bmtf200_2.c and lcd-ili9342_320240.c:

Code: [Select]
struct jzfb_platform_data jzfb_pdata = {
.num_modes = 1,
.modes = &jzfb0_videomode,
.lcd_type = LCD_TYPE_SLCD,
.bpp    = 24,
.width = 31,
.height = 31,
.pinmd  = 0,

.smart_config.rsply_cmd_high       = 0,
.smart_config.csply_active_high    = 0,
.smart_config.newcfg_fmt_conv =  1,
.smart_config.write_gram_cmd = cmd_buf,
.smart_config.clkply_active_rising = 1,
.smart_config.length_cmd = ARRAY_SIZE(cmd_buf),
.smart_config.bus_width = 8,
.smart_config.length_data_table =  ARRAY_SIZE(ili9342_data_table),
.smart_config.data_table = ili9342_data_table,
.dither_enable = 0,
};

and my data struct - which is all messed up, but the first few items seem to make sense:

Code: [Select]
                             jzfb_platform_data                              XREF[1]:     805728e8(*) 
        80514788 01 00 00        jzfb_pla
                 00 14 48
                 51 80 00
           80514788 01 00 00 00     long      1h                      num_modes                         XREF[1]:     805728e8(*) 
           8051478c 14 48 51 80     addr      fb_videomode            *modes        =
           80514790 00 00 00 00     addr      00000000                *dsi_data
           80514794 0d 00 00 80     uint      8000000Dh               lcd_type
           80514798 18 00 00 00     uint      18h                     bpp
           8051479c 1f 00 00 00     uint      1Fh                     width
           805147a0 1f 00 00 00     uint      1Fh                     height
           805147a4 00              uint:1    0h                      pinmd:1
           805147a4 00              uint:1    0h                      pixclk_falli
           805147a4 00              uint:1    0h                      data_enable_
           805147a5 00 00 00 00 00  smart_co                          field_0x1d
                    00 00 11 00 00
                    00 01 00 00 00
              805147a5 00 00 00 00     uint      0h                      smart_type
              805147a9 00              uint:1    0h                      clkply_activ
              805147a9 00              uint:1    0h                      rsply_cmd_hi
              805147a9 00              uint:1    0h                      csply_active
              805147a9 00              uint:1    0h                      newcfg_6800_
              805147a9 00              uint:1    0h                      newcfg_fmt_c
              805147a9 00              uint:1    0h                      datatx_type_
              805147a9 00              uint:1    0h                      newcfg_cmd_9
              805147aa 00 00 11 00     ulong     110000h                 length_cmd
              805147ae 00 00 01 00     addr      00010000                write_gram_cmd
              805147b2 00 00 4c 48     ulong     484C0000h               bus_width
              805147b6 51 80 08 00     uint      88051h                  data_times
              805147ba 00 00 00 00     ulong     0h                      length_data_
              805147be 00 00 38 00     addr      00380000                *data_table
              805147c2 00 00 7c 48     addr      487c0000                (*init)
              805147c6 51 80 00 00     addr      00008051                (*gpio_for_s
              805147ca 00 00 00 00     int       0h                      te_gpio
              805147ce 00 00 00 00     int       0h                      te_irq_level
           805147d2 00              uint:1    0h                      dither_enabl
           805147d3 00 00 00 00 00  dither                            dither
                    00 00 00 00 00
                    00 00
              805147d3 00 00 00 00     uint      0h                      dither_red
              805147d7 00 00 00 00     uint      0h                      dither_green
              805147db 00 00 00 00     uint      0h                      dither_blue
        805147df 00              ??         00h
        805147e0 00              ??         00h
        805147e1 00              ??         00h
        805147e2 00              ??         00h
        805147e3 00              ??         00h

I dunno, I've been playing with it for an hour or 2 and I can't seem to get anything past "height" to make any sense.
« Last Edit: June 19, 2021, 11:48:50 PM by dconrad »
Logged

Offline amachronic

  • Developer
  • Member
  • *
  • Posts: 261
Re: Beginning steps in kernel disassembly and analysis
« Reply #14 on: June 20, 2021, 05:44:40 AM »
0x2c2c2c2c is most definitely the value pointed to by smart_config.write_gram_cmd. 0x2c is the standard write_memory_start command of MIPI DCS, used to initiate writing data to the LCD controller's framebuffer RAM. It's not fb_videomode.flag.

In the M3K kernel sources the init_pixclock member is dropped vs. the YuanhuanLiang repo. That's probably why your fb_videomode struct is too big. Maybe you should check the M3K sources for other structs that seem "wrong", it's possible that the Eros Q is using sources similar to the M3K's. (A reminder that your source won't necessarily line up with the binary!)

So with this in mind, jzfb stuff looks lined up right to me:

Code: [Select]
805147ac = bitfield
             clkply_active_rising=1
             newcfg_fmt_conv=1
             others=0
             (this is standard fare, nothing exotic)
805147b8 = smart_config.bus_width
805147c0 = smart_config.length_data_table
805147c4 = smart_config.data_table

Also a look at this
Code: [Select]
           805147a4 00              uint:1    0h                      pinmd:1
           805147a4 00              uint:1    0h                      pixclk_falli
           805147a4 00              uint:1    0h                      data_enable_
           805147a5 00 00 00 00 00  smart_co                          field_0x1d

That start address 805147a5 is almost certainly wrong. The alignment of the struct is at least 4 bytes and struct alignment = maximum alignment of any member. Plus, the first member must be aligned wrong because enums seem to be ints under the ABI used (an implementation detail which I haven't bothered to verify but seems to be true).

Weirdly, Ghidra doesn't align structs by default -- in the lower right corner of the struct editor is an unobtrusive "Align" checkbox. Checking that will make Ghidra insert the correct padding to follow C alignment rules (afaict). It seems Ghidra defaults to "packed" alignment by default... it confused me for a couple hours too. :o

In this particular case I think I can say with certainty the alignment is wrong -- but in general, you would need to check the generated code to see if the compiler emitted code to access aligned addresses or unaligned addresses. The lw/sw instructions to load/store a word require 4 byte aligned addresses, whereas to access an improperly aligned word, the compiler would need to generate different instructions -- in the case of MIPS the instructions used would depend on the ISA version targeted, IIRC the older versions don't have any unaligned load/store instructions.

Quote from: dconrad on June 19, 2021, 10:38:06 PM
I have a suspicion that the jzfb_platform_data struct is actually the one outlined in arch/mips/xburst/soc-x1000/include/mach/jzfb.h, could this be true?
That's my assumption. Sure, it's defined in other parts of the xburst tree for other SoCs, but this is an X1000 kernel... where else would it be defined?
Logged

  • Print
Pages: [1] 2 3
« previous next »
+  Rockbox Technical Forums
|-+  Rockbox Development
| |-+  Starting Development and Compiling
| | |-+  Beginning steps in kernel disassembly and analysis
 

  • SMF 2.0.19 | SMF © 2021, Simple Machines
  • Rockbox Privacy Policy
  • XHTML
  • RSS
  • WAP2

Page created in 0.069 seconds with 21 queries.