Project

General

Profile

Actions

I9250Bootloader

Accessing the bootloader console

When connected on the serial port, during boot, if you press the volume down button and press enter on the serial console, you can get a shell:

====== VCELL : 409625, SOC : 100, nType : 4 ======
[Charger] nScaledVCELL : 409625000, nDesriedSOC, : 98, nMaxSOC : 118, nMinSOC : 78
* FB base addr = 0xbea70000!
* PANEL_S6E8AA0_ID_READ : 0x12, 0x8e, 0x9b.
[ omap_power_get_reset_source :47]     PRM_RSTST : 0x2

Autoboot (1 seconds) in progress, press any key to stop .

Autoboot aborted..
SBL> 
SBL> 
SBL> 
SBL> help
Following commands are supported:
* setenv
* saveenv
* printenv
* help
* reset
* boot
* kernel
* loadpart
* loadkernel
* erasepart
* omap_upload_rdx
* omap_test_button
* omap_test_hwinfo
* omap_set_gpio_level
* omap_get_gpio_level
* omap_test_twl6030
* omap_test_power
* omap_reboot
* omap_halt
* omap_cmdline_power
* omap_test_kbd
* omap_test_usbacc
* usb
* omap_test_max17043
* omap_test_fsa9480
* omap_dump_sec_log_buf
* omap_test_sud
To get commands help, Type "help <command>" 
SBL> 

Available commands

Here's the known list of commands:

SBL> help
Following commands are supported:
* setenv
* saveenv
* printenv
* help
* reset
* boot
* kernel
* loadpart
* loadkernel
* erasepart
* omap_upload_rdx
* omap_test_button
* omap_test_hwinfo
* omap_set_gpio_level
* omap_get_gpio_level
* omap_test_twl6030
* omap_test_power
* omap_reboot
* omap_halt
* omap_cmdline_power
* omap_test_kbd
* omap_test_usbacc
* usb
* omap_test_max17043
* omap_test_fsa9480
* omap_dump_sec_log_buf
* omap_test_sud
To get commands help, Type "help <command>" 
SBL> 

And their respective help:

SBL> help setenv
* Help : setenv
* Usage : setenv [name] [value] . .
    Modify current environment info on ram

SBL> help saveenv
* Help : saveenv
* Usage : saveenv
    Save cuurent environment info to flash

SBL> help printenv
* Help : printenv
* Usage : printenv
    Print current environment info on ram

SBL> help help
* Help : help
* Usage : help [command]
SBL> help reset
* Help : reset
* Usage : reboot
Reboot system

SBL> help boot
* Help : boot
* Usage : boot [kernel options]
Boot Linux with optional kernel options

SBL> help kernel
* Help : kernel
* Usage : kernel hex_adr
Change the Linux kernel base

SBL> help loadpart
* Help : loadpart
* Usage : load partition from storage device.
SBL> help loadkernel
* Help : loadkernel
* Usage : load kernel from storage device.
SBL> help erasepart
* Help : erasepart
* Usage : erase partition.
SBL> help omap_upload_rdx
* Help : omap_upload_rdx
* Usage : [OMAP] upload RDX
    omap_upload_rdx
SBL> help omap_test_button
* Help : omap_test_button
* Usage : [OMAP] test OMAP buttons
    omap_test_button
SBL> help omap_test_hwinfo
* Help : omap_test_hwinfo
* Usage : [OMAP] test OMAP HW Information
    omap_test_hwinfo
SBL> help omap_set_gpio_level
* Help : omap_set_gpio_level
* Usage : [OMAP] set GPIO level
    omap_set_gpio_level {GPIO} {VALUE}
SBL> help omap_get_gpio_level
* Help : omap_get_gpio_level
* Usage : [OMAP] get GPIO level
    omap_get_gpio_level {GPIO}
SBL> help omap_test_twl6030
* Help : omap_test_twl6030
* Usage : [OMAP] test twl6030 device
    omap_test_twl6030
SBL> help omap_test_power
* Help : omap_test_power
* Usage : [OMAP] test power function
    omap_test_power
SBL> help omap_reboot
* Help : omap_reboot
* Usage : [OMAP] system reboot command
    omap_reboot
SBL> help omap_halt
* Help : omap_halt
* Usage : [OMAP] system halt command
    omap_halt
SBL> help omap_cmdline_power
* Help : omap_cmdline_power
* Usage : [OMAP] check kernel-cmdline by power
    omap_cmdline_power
SBL> help omap_test_kbd
* Help : omap_test_kbd
* Usage : [OMAP] test power function
    omap_test_kbd
SBL> help omap_test_usbacc
* Help : omap_test_usbacc
* Usage : [OMAP] test OMAP usb-accessary
    omap_test_usbacc
SBL> help usb
* Help : usb
* Usage : usb download command
SBL> help omap_test_max17043
* Help : omap_test_max17043
* Usage : [OMAP] test max17043 device
    omap_test_max17043
SBL> help omap_test_fsa9480
* Help : omap_test_fsa9480
* Usage : [OMAP] test fsa9480 device
    omap_test_fsa9480
SBL> help omap_dump_sec_log_buf
* Help : omap_dump_sec_log_buf
* Usage : [OMAP] dump sec-log-buf
    omap_dump_sec_log_buf
SBL> help omap_test_sud
* Help : omap_test_sud
* Usage : [OMAP] test SUD image
    omap_test_sud {NUMBER}
SBL> 

Changing the kernel commandline arguments

I've tried to modify the CMDLINE:

SBL> setenv CMDLINE loglevel=8 console=ttyFIQ0 androidboot.console=ttyFIQ0
argv[0] : setenv
argv[1] : CMDLINE
argv[2] : loglevel=8 console=ttyFIQ0 androidboot.console=ttyFIQ0
value : 656175548
SBL> saveenv
save_param start block=49152, no.blocks=16384

But once booted, "loglevel=8" wasn't found in /proc/cmdline on Replicant 6.0 0003 so it doesn't seem to have an impact. Though, on this bootloader, the commandline can also be modified by modifying the boot.img commandline parameters.

Other commands

SBL> omap_test_hwinfo
-----------------------------------------------------------
   OMAP-Samsung HW Information

   Board  Name : tuna  REV 9
   Board  Rev  : HSPA - 9
   Boot   Type : USB MMC1
   Device Type : HS
   Build Date  : Jan 24 2012 18:27:20
-----------------------------------------------------------
SBL> printenv
PARAM Rev 1.6
SERIAL_SPEED : 7
LOAD_RAMDISK : 0
BOOT_DELAY : 1
LCD_LEVEL : 6
SWITCH_SEL : 3
PHONE_DEBUG_ON : 0
LCD_DIM_LEVEL : 0
LCD_DIM_TIME : 6
MELODY_MODE : 1
REBOOT_MODE : 0
NATION_SEL : 0
LANGUAGE_SEL : 0
SET_DEFAULT_PARAM : 0
OFF_MODE_CHARGE : 1
FLASH_LOCK_STATUS : 0
VERSION : 
CMDLINE : 
DELTA_LOCATION : /mnt/rsv
WIFI_MAC_LINE : 
PARAM_STR_4 : DCM

Reboot interface

The installation instructions use Heimdall to install the Replicant recovery on the Galaxy Nexus (GT-I9250) in order to have unified installation instructions, so it would be great to be able to reboot to the bootloader mode that is compatible with heimdall with a command (like reboot download or adb reboot download), especially to be able to run automatic installation tests, but that doesn't look possible. The following explains why.

In arch/arm/mach-omap2/board-tuna.c in the Replicant 6.0 kernel_samsung_tuna, there is the following code:

#define REBOOT_FLAG_RECOVERY    0x52564352
#define REBOOT_FLAG_FASTBOOT    0x54534146
#define REBOOT_FLAG_NORMAL      0x4D524F4E
#define REBOOT_FLAG_POWER_OFF   0x46464F50
[...]
static int tuna_notifier_call(struct notifier_block *this,
                                        unsigned long code, void *_cmd)
{
        void __iomem *sar_base;
        unsigned int flag = REBOOT_FLAG_NORMAL;

        sar_base = omap4_get_sar_ram_base();

        if (!sar_base)
                return notifier_from_errno(-ENOMEM);

        if (code == SYS_RESTART) {
                if (_cmd) {
                        if (!strcmp(_cmd, "recovery"))
                                flag = REBOOT_FLAG_RECOVERY;
                        else if (!strcmp(_cmd, "bootloader"))
                                flag = REBOOT_FLAG_FASTBOOT;
                }
        } else if (code == SYS_POWER_OFF) {
                flag = REBOOT_FLAG_POWER_OFF;
        }

        /* The Samsung LOKE bootloader will look for the boot flag at a fixed
         * offset from the end of the 1st SAR bank.
         */
        writel(flag, sar_base + SAR_BANK2_OFFSET - 0xC);

        return NOTIFY_DONE;
}

If we look at the defines, we can see a pattern:
#define value ASCII ASCII with opposite endianess
REBOOT_FLAG_RECOVERY 0x52564352 RVCR RCVR
REBOOT_FLAG_FASTBOOT 0x54534146 TSAF FAST
REBOOT_FLAG_NORMAL 0x4D524F4E MRON NORM
REBOOT_FLAG_POWER_OFF 0x46464F50 FFOP POFF

So if we patch the kernel with the following patch, we are able to test various flags values:

diff --git a/arch/arm/mach-omap2/board-tuna.c b/arch/arm/mach-omap2/board-tuna.c
index 43aaf6f38e76..7da64734df84 100755
--- a/arch/arm/mach-omap2/board-tuna.c
+++ b/arch/arm/mach-omap2/board-tuna.c
@@ -1128,6 +1128,15 @@ static int tuna_notifier_call(struct notifier_block *this,
                                flag = REBOOT_FLAG_RECOVERY;
                        else if (!strcmp(_cmd, "bootloader"))
                                flag = REBOOT_FLAG_FASTBOOT;
+                       else if (strlen(_cmd) == 4) {
+                               int i;
+                               char* cmd = _cmd;
+                               flag = (cmd[0] << 24) | (cmd[1] << 16) | (cmd[2] << 8) | (cmd[3]);
+
+                               for (i=1000; i>0; i--) {
+                                       printk(KERN_INFO "%s: #%d reboot [%s] => 0x%x", __func__, i, cmd, flag);
+                               }
+                       }
                }
        } else if (code == SYS_POWER_OFF) {
                flag = REBOOT_FLAG_POWER_OFF;

With the patch above, adb reboot TSAF will make the device reboot to the fastboot mode and adb reboot FFOP will power off the device.

Since FAST and POFF are strings inside the bootloader that is in the SBL partition, I coded a python script to test all the 4 letter uppercase strings found inside that partition:

#!/usr/bin/env python3
#
# Copyright (C) 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import re
from sh import adb
import string
import sys

# From sysexits.h
EX_USAGE = 64  # command line usage error

class Log(object):
    def __init__(self):
        self.log_path = re.sub("\.py$", "", sys.argv[0]) + ".log" 
        self.file = open(self.log_path, 'a')

    def print(self, string):
        print(string)
        self.file.write(string + os.linesep)

    def close(self):
        self.file.close()

def usage(progname):
    print("Usage: {} bruteforce [start]".format(progname))
    print("Example: {} bruteforce BAAA".format(progname))
    sys.exit(EX_USAGE)

def is_uppercase(s):
    for c in s:
        if c not in string.ascii_uppercase[:26]:
            return False
    return True

def bruteforce(start='AAAA'):
    start0 = string.ascii_uppercase[:26].index(start[0])
    start1 = string.ascii_uppercase[:26].index(start[1])
    start2 = string.ascii_uppercase[:26].index(start[2])
    start3 = string.ascii_uppercase[:26].index(start[3])

    log = Log()

    for l1 in string.ascii_uppercase[start0:26]:
        for l2 in string.ascii_uppercase[start1:26]:
            for l3 in string.ascii_uppercase[start2:26]:
                for l4 in string.ascii_uppercase[start3:26]:
                    reboot_cmd = "{}{}{}{}".format(l1, l2, l3, l4)
                    adb("wait-for-recovery")
                    log.print("reboot {}".format(reboot_cmd))
                    adb("reboot", reboot_cmd)
    log.close()

def dictionary():
    strings = [
        'BOOT',
        'DUDD',
        'EDUQ',
        'FAST',
        'FGIQ',
        'GTHP',
        'GTPY',
        'HALT',
        'HFHO',
        'HSPA',
        'IWFR',
        'JFIF',
        'KKXA',
        'LAST',
        'LOKE',
        'MDED',
        'MYIB',
        'NAND',
        'NDED',
        'NORM',
        'NQST',
        'NRZM',
        'ODIN',
        'OKAY',
        'POFF',
        'PXQE',
        'QAAE',
        'QUMC',
        'RCVR',
        'RMFO',
        'RSET',
        'SNBL',
        'STAR',
        'XMWQ',
    ]

    log = Log()
    for entry in strings:
        reboot_cmd = entry[3] + entry[2] + entry[1] + entry[0]
        adb("wait-for-recovery")
        log.print("reboot {}".format(reboot_cmd))
        adb("reboot", reboot_cmd)
    log.close()

if len(sys.argv) == 2 and sys.argv[1] == "bruteforce":
    bruteforce()
elif len(sys.argv) == 3 and sys.argv[1] == "bruteforce":
    if len(sys.argv[2]) == 4 and is_uppercase(sys.argv[2]):
        start = sys.argv[1]
        bruteforce(start)
    else:
        usage(sys.argv[0])
if len(sys.argv) == 2 and sys.argv[1] == "dictionary":
    dictionary()
elif len(sys.argv) != 1:
    usage(sys.argv[0])

But it didn't find a way to boot to the heimdall compatible mode, so we now either need to implement fastboot in the tests or to test the Galaxy Nexus manually (which is more time consuming and way more error prone). Because of that limitation, we would not be able to have the installation instructions tested automatically.

The fact that the bootloader is signed and that the second stage (SBL) is not free software prevents us from fixing that issue.

It might still be possible to replace the second stage with u-boot though, but it would require to redistribute a signed bootloader that is under free a software license but practically nonfree as users can't run modified versions.

Updated by Denis 'GNUtoo' Carikli 6 months ago · 11 revisions

Also available in: PDF HTML TXT