Google Galaxy Nexus (samsung-maguro): Mainlining progress
I will track here my progress of mainlining the Google (Samsung) Galaxy Nexus Model GT-I9250 (samsung-maguro).
The device has the OMAP4460 SoC which already have some support in the latest kernel.
Starting with the porting of this device was quite difficult without any output from the device.
So I've decided to follow the simplest trial and error procedure that came to my mind: patch the kernel init process with some sleep
and emergency_restart
calls in order to understand which part of code was failing. (see below for more details)
Apart from this, many thanks to @zhuowei with the Google Pixel 3 XL (google-crosshatch) porting because I followed the same procedure he described in #153 (closed) in order to get the logs.
Current Status (22.01.2019)
-
Kernel boots -
Initramfs script works -
No usb/serial output after kernel starts (only bootloader output) -
RAM mapped in DTS -
Kernel patched to dump the dmesg log to a reserved memory space -
After a kernel panic and rebooted in the downstream kernel, the /proc/last_kmesg
contains the log🎉
Current Status (23.04.2019)
-
USB works -
MMC works
Current Status (26.04.2019)
-
fuelgauge works (battery voltage, capacity and charging/discharging status) -
battery charger works -
volume/power keys -
accelerometer works -
gyroscope works
Current Status (16.05.2019)
-
display works (simple-framebuffer)
Current Status (06.06.2019)
-
audio works (earphone only) -
barometer works
Next steps
-
Investigate audio regression on kernel 5.2 -
Investigate clock issue of the display -
Investigate the firmware loading issues with the MELFAS MMS144 touchscreen driver -
Port the downstream magnetometer driver (yas530) and add device tree bindings support -
Add device tree bindings support to the mainline proximity sensor driver (gp2a)
Future steps
-
Enable the FSA9480 driver and configure it to redirect the serial to the usb (unfortunately this driver doesn't have DT bindings) -
Investigate the problematic, temporary commented out code, to find a better solution (maybe disabling the some nodes in the DTB) -
everything else
How the mainlining process started...
preparation
- Flashed the device with the
debug-shell
hook in order to have a working situation on normal boots - Pulled the latest kernel sources (v5.0-rc2)
- Copied the
omap2plus_defconfig
and then ranmake menuconfig
to use the defaults for newly added params - Created a stub
omap4-samsung-maguro.dtb
and added it to thearch/arm/boot/dts/Makefile
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "omap4460.dtsi"
/ {
model = "Samsung Galaxy Nexus";
compatible = "ti,tuna", "ti,omap4460", "ti,omap4";
};
- Compiled the kernel using the envkernel.sh script
- Prepared a custom script which append the dtbo the the kernel, creates a boot.img and does a
fastboot boot
in order to send it to the device
first trials & errors
- Configure the kernel to wait forever when a panic occur (
CONFIG_PANIC_TIMEOUT=0
) - Start patching the kernel init process with some sleep (delay.h) calls and
emergency_restart
(reboot.h) - Measure the time from the boot and the forced restart and figure out where it goes wrong...
Using this approach, after some hours I've managed to find two issue that by skipping them they let me reach the initramfs script
The main entry function I've started investigating was the kernel_init
which is the thread with the pid 1 (source).
Example:
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
ftrace_free_init_mem();
...
By adding a emergency_restart();
before the kernel_init_freeable();
and booting it, the device was restarting immediately, by placing the emergency_restart();
right after, the device was hanging there forever.
So I began to move more and more deeply into the various functions.
kernel_init
└ kernel_init_freeable
└ ...
└ do_basic_setup
└ cpuset_init_smp
└ shmem_init
└ driver_init
└ init_irq_proc
└ do_ctors
└ usermodehelper_enable
└ do_initcalls
└ ...
└ (all the registered pure/core/postcore/arch/subsys/fs/device/late init calls)
└ ...
And so on, until I've found some problematic clocks defined here that were called during the postcore_initcall
in omap_hwmod.c
omap44xx_l3_main_2__aes1
omap44xx_l3_main_2__aes2
omap44xx_l3_main_2__des
omap44xx_l3_main_2__sha0
and also the omap4_idle_init
(source] was causing some trouble and I've decided to comment it out.
With these "fixes", I've managed to reach the kernel init process code with the long-awaited comment
Ok, we have completed the initial bootup, and we're essentially up and running.
and the start of the initramfs.
second phase, initramfs
Nothing much to do in the initramfs since we don't have anything to interact with, so let's just use the postmarketOS initramfs script with a echo c > /proc/sysrq-trigger
right after the mount_proc_sys_dev
function.
Also reconfigure the kernel to actually reboot when it panics (CONFIG_PANIC_TIMEOUT=-1
)
NOTE: The initfs kernel-panic
hook basically does the same thing, but I've preferred to avoid the additional steps that are still in between (modprobe
, setup_mdev
, mount_subpartitions
, setup_framebuffer
,...). So we really should move the hook earlier (pmbootstrap#1607 (closed)) to avoid other kind of errors/delays.
third phase, dump kernel logs
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
- Reserved the RAM region at the address where the downstream kernel looks for the data omap_ram_console.h#L21
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
ramoops_region@A0000000 {
no-map;
reg = <0xA0000000 0x200000>;
};
};
- Patch the panic function in the kernel to write the logs at the reserved region just before rebooting panic.c#L309
NOTE: the downstream kernel ram_console expects a specific signature at the beginning of the specific memory location (ram_console.c#L301-L316) and also disabled the CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
which encode/decode the data in some rs8 parity buffer (don't know what it is)
Example:
@@ -306,6 +306,15 @@ void panic(const char *fmt, ...)
* shutting down. But if there is a chance of
* rebooting the system it will be rebooted.
*/
+ void* alt_ramoops = ioremap(0xA0000000, 0x200000);
+ memset(alt_ramoops, 'A', 0x200000); // clear
+ uint32_t sig = 0x43474244;
+ uint32_t start = 0;
+ uint32_t size = 0x1FFFF4;
+ memcpy(alt_ramoops, &sig, 4);
+ memcpy(alt_ramoops+4, &start, 4);
+ memcpy(alt_ramoops+8, &size, 4);
+ memcpy(alt_ramoops+12, log_buf_addr_get(), min(log_buf_len_get(), 0x1FFFF4));
emergency_restart();
}