您的位置:首页 > 其它

高通 MSM8K bootloader 之二: SBL1

2017-01-15 23:30 417 查看
http://blog.csdn.net/fybon/article/details/37565227

续:高通 MSM8K bootloader 之一: SBL1

上篇将我重点关注SBL1的内容1和2基本说明完,本篇继续内容3和4。

1、 CDT : Platform ID和DDR参数

2、 debug log :

3、 download : msm8K 新平台软件download支持两种协议,sahara和firehose

4、 ramdump :死机异常信息dump

四、SW download

1、软件升级模式

  高通8K以后平台支持如下两种,说到下载模式,忍不住又得骂高通。 
  以前6K, 7K平台不支持紧急下载模式,工厂生产软件要down到手机里,非常复杂。
  要嘛先用烧录器烧一段sbl image,然后剩下的image自己开发升级软件用usb多路升级。
  要嘛全部image用烧录器一次性烧完。
  坑人的高通啊!么得办法,就害苦咱苦命的民工。 好了,介绍一下现在支持的两种下载模式吧! 
  紧急下载模式:pbl负责与PC交互,实现软件下载
  自动进入紧急下载模式:主板刚生产emmc是裸片时,或者sbl运行异常时,系统自动进入紧急下载模式。
            这种情况就不多说了,主要是用于工厂生产,及sbl异常处理。

  手动进入紧急下载模式:通过硬件一个gpio下拉,pbl检测到该gpio后强制进入紧急下载模式。这种主要
             以防不测情况。
   另外一种就是软件通过设置magic number,然后由热重启,pbl检测到magic number后,强制进入下载模式。

  软件切换接口,参考如下boot_dload.c代码:

[cpp] view
plain copy

print?





/*=============================================================================

** Function : boot_dload_transition_pbl_forced_dload

** ==========================================================================

*/

/*!

*

* @brief

* This function sets the magic numbers for PBL to detect and enter forced

* download mode. It then calls the target specific function to trigger a

* system reset.

*

* @par Dependencies

* None

*

* @retval

* None

*

* @par Side Effects

* Set's PBL magic numbers to enter forced download, resets target, never to

* return.

*

*/

void <strong>boot_dload_transition_pbl_forced_dload</strong>( void )

{

/* PBL uses the last four bits of BOOT_MISC_DETECT to trigger forced download.

Preserve the other bits of the register. */

uint32 register_value =

HWIO_TCSR_BOOT_MISC_DETECT_INM(HWIO_TCSR_BOOT_MISC_DETECT_RMSK);

/* Clear the PBL masked area and then apply HS_USB value */

register_value &= ~(FORCE_DLOAD_MASK);

register_value |= FORCE_DLOAD_HS_USB_MAGIC_NUM;

/* Write the new value back out to the register */

HWIO_TCSR_BOOT_MISC_DETECT_OUTM(FORCE_DLOAD_MASK,

register_value);

boot_hw_reset(BOOT_WARM_RESET_TYPE);

} /* boot_dload_transition_pbl_forced_dload() */

 普通下载模式:sbl负责与PC交互,实现软件下载
 手机第一次下载完软件以后,普通情况下,可不进入pbl紧急下载模式,可由sbl进行软件升级。
 sbl是如何进入普通下载模式的呢?看如下函数boot_dload_check()。
 boot_dload_check()检测到USB D+ 接地或者sbl发生异常时调用boot_dload_set_cookie()设置了cookie,进自  动进入普通的下载模式。

[cpp] view
plain copy

print?





<pre name="code" class="cpp">

/*===========================================================================

** Function : boot_dload_check

** ==========================================================================

*/

/*!

*

* @brief

* This function will check to see if the downloader should be entered

* for QPST download, and enter the downloader if directed to.

*

* @param[in] bl_shared_data Pointer to the shared data

*

* @par Dependencies

* Download ID must be present in IRAM if downloader is to be entered.

*

* @retval

* None

*

* @par Side Effects

* Boot may be halted and QPST downloader entered.

*

*/

void boot_dload_check

(

bl_shared_data_type *bl_shared_data

)

{

/* Check whether USB D+ line is grounded. If it is, then enter

PBL Download mode */

<strong><span style="color:#cc0000;"> if(boot_qhsusb_al_check_for_pbl_dload(0))

{

boot_dload_transition_pbl_forced_dload();

}</span></strong>

/* Determine if the downloader should be entered at this time,

instead of continuing with the normal boot process. */

if ( boot_dload_entry( ) == TRUE )

{

/* Check the UEFI ram dump cookie, we enter download mode

only if UEFI ram dump cookie is NOT set*/

if ( !( boot_shared_imem_cookie_ptr != NULL &&

boot_shared_imem_cookie_ptr->uefi_ram_dump_magic ==

UEFI_CRASH_DUMP_MAGIC_NUM ) )

{

/* Before entering downloader clear RESET_DEBUG[BLOCK_RESIN] so

the next resin_n is not blocked. This is part of the abnormal

reset logic in Bear family */

HWIO_GCC_RESET_DEBUG_OUTM(HWIO_GCC_RESET_DEBUG_BLOCK_RESIN_BMSK,

0);

/* Enter downloader for QPST */

sbl_dload_entry();

}

}

} /* boot_dload_check() */



[cpp] view
plain copy

print?





/*===========================================================================

** Function : boot_dload_set_cookie

** ==========================================================================

*/

/*!

*

* @brief

* Set the SBL dload mode cookie

**

* @par Dependencies

* None

*

*/

void boot_dload_set_cookie()

{

HWIO_TCSR_BOOT_MISC_DETECT_OUTM(SBL_DLOAD_MODE_BIT_MASK,

SBL_DLOAD_MODE_BIT_MASK);

}

再看看下面的代码!!! 我们又有新的发现!
sbl1_target.c

[cpp] view
plain copy

print?





<pre name="code" class="cpp">/*===========================================================================

** Function : sbl_dload_entry

** ==========================================================================

*/

/*!

*

* @brief

* This function pointer is defined in each SBL* Bootloader to handle SBL-specific

* requirements to enter a download routine. It is initialized to

* boot_dload_transition_pbl_forced_dload by default.

*

* @par Dependencies

* None

*

* @retval

* None

*

* @par Side Effects

* None

*

*/

void (*sbl_dload_entry)(void) = boot_dload_transition_pbl_forced_dload;

函数指针sbl_dload_entry默认指向紧急下载模式的入口:boot_dload_transition_pbl_forced_dload ,
该下载方式会切换到pbl,由pbl通过firehose协议实现download。



[cpp] view
plain copy

print?





void sbl1_dload_entry ()

{

static uint32 dload_entry_count = 0;

dload_entry_count++;

/* Only execute the pre-dload procedures the first time we try to enter

* dload in case there is an error within these procedures. */

if( dload_entry_count == 1 && &bl_shared_data != NULL )

{

/* Entering dload routine for the first time */

<strong>boot_do_procedures</strong>( &bl_shared_data, sbl1_pre_dload_procs );

}

pm_device_config_in_dloadmode();

/* Enter boot Sahara */

<strong>boot_dload_transition_enter_sahara</strong>();

}/* sbl1_dload_entry() */

而sbl1定义了另一个下载模式的入口:sbl1_dload_entry,它支持直接在sbl1中通过sahara协议download,
还支持crash ram dump 功能。包括dump to raw partition ,and dump to sdcard 。
见:boot_do_procedures( &bl_shared_data, sbl1_pre_dload_procs ); 
crash ramdump章节再详细看看。

sbl1_mc.c

[cpp] view
plain copy

print?





<pre name="code" class="cpp">/*DLOAD flag for SBL1 to enter PBL error handler*/

#ifdef BOOT_ENTER_PBL_DLOAD_ON_SBL_ERROR

static boot_boolean edload_flag = TRUE;

#else

static boot_boolean edload_flag = FALSE;

#endif



[cpp] view
plain copy

print?





</pre><pre name="code" class="cpp">void sbl1_post_ddr_init(bl_shared_data_type *bl_shared_data)

{

..........

if (edload_flag != TRUE)

{

/* Update the dload entry to sbl1 sahara dload entry function */

sbl_dload_entry = sbl1_dload_entry;

}

}

好,既然在sbl1有两个download入口,如何选则呢?

sbl1_mc.c 中通过宏BOOT_ENTER_PBL_DLOAD_ON_SBL_ERROR控制。
如果定义该宏,则dload处理会转交给PBL帮忙处理了。

2、进入升级模式的方法

  上节描述的高通默认进入下载模式的方法,都是自动的,显然无法满足开发、生产、售后等需求。
  因此如下两种方法,实用于开发、生产、售后。

  sbl1扫描按键组合:
  关机状态下,sbl1扫描按键组合,比如,扫描到power & vol+ 两个按键同时按下,则进入pbl紧急下模模式。
  当然,有些结构设计可能导致power & vol+ 两个按键开机容易误触,则可以采用别的硬件组合方式。比如,
  vol+ & usb 等等!

  关机状态,进入下载模式,没有ram dump的需求,因此当扫描到相应的硬件组合,
  直接调用:boot_dload_transition_pbl_forced_dload

  adb reboot + edl / dload :
手机正常开机,能连接usb上的状态下,可以使用 adb reboot edl 或者 adb reboot dload 命令,
  使手机进入pbl紧急下载模式,或者进入sbl1普通下载模式。 

  MSM8916平台参考如下代码,
  kernel/drivers/power/reset/msm-poweroff.c ,相关代码由宏CONFIG_MSM_DLOAD_MODE控制。

[cpp] view
plain copy

print?





static int msm_restart_probe(struct platform_device *pdev)

{

struct device *dev = &pdev->dev;

struct resource *mem;

struct device_node *np;

int ret = 0;

#ifdef CONFIG_MSM_DLOAD_MODE

if (scm_is_call_available(SCM_SVC_BOOT, SCM_DLOAD_CMD) > 0)

scm_dload_supported = true;

atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);

np = of_find_compatible_node(NULL, NULL, DL_MODE_PROP);

if (!np) {

pr_err("unable to find DT imem DLOAD mode node\n");

} else {

dload_mode_addr = of_iomap(np, 0);

if (!dload_mode_addr)

pr_err("unable to map imem DLOAD offset\n");

}

np = of_find_compatible_node(NULL, NULL, EDL_MODE_PROP);

if (!np) {

pr_err("unable to find DT imem EDLOAD mode node\n");

} else {

emergency_dload_mode_addr = of_iomap(np, 0);

if (!emergency_dload_mode_addr)

pr_err("unable to map imem EDLOAD mode offset\n");

}

set_dload_mode(download_mode);

#endif

np = of_find_compatible_node(NULL, NULL,

"qcom,msm-imem-restart_reason");

if (!np) {

pr_err("unable to find DT imem restart reason node\n");

} else {

restart_reason = of_iomap(np, 0);

if (!restart_reason) {

pr_err("unable to map imem restart reason offset\n");

ret = -ENOMEM;

goto err_restart_reason;

}

}

mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

msm_ps_hold = devm_ioremap_resource(dev, mem);

if (IS_ERR(msm_ps_hold))

return PTR_ERR(msm_ps_hold);

pm_power_off = do_msm_poweroff;

arm_pm_restart = do_msm_restart;

if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0)

scm_pmic_arbiter_disable_supported = true;

return 0;

err_restart_reason:

#ifdef CONFIG_MSM_DLOAD_MODE

iounmap(emergency_dload_mode_addr);

iounmap(dload_mode_addr);

#endif

return ret;

}

msm_restart_probe函数在执行过程中打印出如下log,说明dts中没有设置emergency_dload_mode_addr,及dload_mode_addr的地址。

<3>[ 6.627538] unable to find DT imem DLOAD mode node

<3>[ 6.628075] unable to find DT imem EDLOAD mode node

但添加scm_dload_supported的打印信息,可以看到如下log,
<3>[ 6.626976] scm_dload_supported=1 ,

说明,scm dload是支持的。因此,接下来的两个函数,都是通过scm dload实现download模式切换。

[cpp] view
plain copy

print?





static void enable_emergency_dload_mode(void)

{

int ret;

if (emergency_dload_mode_addr) {

__raw_writel(EMERGENCY_DLOAD_MAGIC1,

emergency_dload_mode_addr);

__raw_writel(EMERGENCY_DLOAD_MAGIC2,

emergency_dload_mode_addr +

sizeof(unsigned int));

__raw_writel(EMERGENCY_DLOAD_MAGIC3,

emergency_dload_mode_addr +

(2 * sizeof(unsigned int)));

/* Need disable the pmic wdt, then the emergency dload mode

* will not auto reset. */

qpnp_pon_wd_config(0);

mb();

}

if (scm_dload_supported) {

ret = scm_call_atomic2(SCM_SVC_BOOT,

SCM_DLOAD_CMD, SCM_EDLOAD_MODE, 0);

if (ret)

pr_err("Failed to set EDLOAD mode: %d\n", ret);

}

}

使能紧急下载模式。

[cpp] view
plain copy

print?





static void set_dload_mode(int on)

{

int ret;

if (dload_mode_addr) {

__raw_writel(on ? 0xE47B337D : 0, dload_mode_addr);

__raw_writel(on ? 0xCE14091A : 0,

dload_mode_addr + sizeof(unsigned int));

mb();

}

if (scm_dload_supported) {

ret = scm_call_atomic2(SCM_SVC_BOOT,

SCM_DLOAD_CMD, on ? SCM_DLOAD_MODE : 0, 0);

if (ret)

pr_err("Failed to set DLOAD mode: %d\n", ret);

}

dload_mode_enabled = on;

}

使能普通下载模式。
这样adb reboot edl 或者 adb reboot dload 命令就可以使手机进入下载模式了。

3、软件升级工具及协议

高通平台,从MSM6K 、7K 到8K, download的方法和协议,一直在更新。
协议经历了从stream dload到sahara,再到现在firehose 。
每一种协议的具体描述参考如下文档:
80-V5348-1_J_Streaming_DLoad_Protocol.pdf

80-N1008-1_H_SaharaProtocolSpecification.pdf

80-NG319-1_A_Firehose Protocol V1.0_Def_Doc.pdf

参见本人的另一篇介绍《qualcomm 8K平台Sahara Protocol相对7K,
6K 平台Software Download优点》。

根据使用不同协议,相应的,高通提供两个下载工具:eMMC Software Download 和 QFIL (Qualcomm Flash Image Loader )

如下俩图 :



通过这种普通下载模式,进入下载模后,windows设备管理器可以看到PC端枚举出一个9006的USB端口,

同时枚举出一个mass storage。

高通这种mass storage模式下载速率是非常的快。可是我也它有如下一些缺点:

pc端枚举mass storage速度很慢,根据测试也非常耗cpu。

pc端枚举mass storage容易出错,特别是多台手机同时枚举时。

纠错不易,按文件方式写入,目前我还没想到什么方法进行纠错?

好,下面贴相关代码所在的路径,及调用到的重要函数贴出来!

boot_images/core/storage/tools/emmcbld

boot_images/core/boot/secboot3/hw/msm8916/sbl1/

sbl1_mc.c

sbl1_target.c

sbl1_sahara.c

boot_images/core/boot/secboot3/src/

boot_sahara.c

boot_extern_hsusb_interface.c

boot_images/core/wiredconnectivity/qhsusb/src/al/qhsusb_al_bulk.c

boot_images/core/wiredconnectivity/qhsusb/src/func/

qhsusb_fd_hdlc.c

qhsusb_fd_ms.c

qhsusb_scsi.c

[cpp] view
plain copy

print?





void sbl1_dload_entry ()

{

static uint32 dload_entry_count = 0;

dload_entry_count++;

/* Only execute the pre-dload procedures the first time we try to enter

* dload in case there is an error within these procedures. */

if( dload_entry_count == 1 && &bl_shared_data != NULL )

{

/* Entering dload routine for the first time */

boot_do_procedures( &bl_shared_data, sbl1_pre_dload_procs );

}

pm_device_config_in_dloadmode();

/* Enter boot Sahara */

boot_dload_transition_enter_sahara();

}/* sbl1_dload_entry() */

[cpp] view
plain copy

print?





/*===========================================================================

** Function : boot_dload_transition_enter_sahara

** ==========================================================================

*/

/*!

*

* @brief

* This function is implemented in each SBL to enter sahara dload mode

*

* @par Dependencies

* None

*

* @retval

* None

*

* @par Side Effects

* None

*

*/

void boot_dload_transition_enter_sahara(void)

{

/* Get Sahara interface */

struct boot_sahara_interface* sbl_sahara_interface = sbl_sahara_get_interface();

BL_VERIFY(sbl_sahara_interface != NULL, BL_ERR_NULL_PTR);

/* Set Sahara mode to memory debug */

sbl_sahara_interface->sahara_mode = SAHARA_MODE_MEMORY_DEBUG;

/* Flush the cache before calling into sahara so that all data is flushed to memory */

mmu_flush_cache();

/* Enter Sahara */

boot_sahara_entry(sbl_sahara_interface);

}

调用sbl_sahara_get_interface获取sahara如下函数接口:sbl_sahara_interface

调用boot_sahara_entry。

[cpp] view
plain copy

print?





/* SBL Sahara dispatch table */

static struct boot_sahara_dispatch_tbl sbl_sahara_dispatch_tbl =

{

SAHARA_INTERFACE_DISPATCH_VERSION,

sbl_sahara_bulk_init,

boot_qhsusb_al_bulk_shutdown,

boot_qhsusb_al_bulk_poll,

(sahara_rx_bulk_type) sbl_sahara_rx_bulk,

(sahara_tx_bulk_type) boot_qhsusb_al_bulk_transmit,

boot_qhsusb_al_bulk_get_max_packet_size,

sbl_sahara_reset,

boot_clobber_check_global_whitelist_range,

sbl_sahara_exec_cmd,

boot_qhsusb_al_bulk_get_max_raw_data_size,

sbl_sahara_is_auth_enabled,

qmemcpy,

qmemset,

sbl_sahara_get_bin_header_size,

sbl_sahara_get_bin_image_id,

sbl_sahara_get_bin_image_dest,

sbl_sahara_get_bin_image_size,

sbl_sahara_get_bin_code_size,

sbl_sahara_get_bin_cert_chain_size,

sbl_sahara_get_bin_signature_size,

sbl_sahara_get_bin_image_src,

sbl_sahara_unrecoverable_error_handler,

sbl_sahara_image_load_post_proc,

sbl_sahara_skip_image_load,

boot_get_hash_segment_buffer,

sbl_elf_optimized_segment_load,

NULL,

NULL,

};

[cpp] view
plain copy

print?





/* ============================================================================

** Function : boot_sahara_entry

** ============================================================================

*/

/*!

* @brief

* This function provides an entry into the Sahara protocol and jumps into

* the protocol.

*

* @details

* This function initializes the Sahara protocol followed by sending a HELLO

* packet to the host. After that, the target will proceed to wait for

* incoming packets and handle them appropriately.

*

* @param sahara_interface - [IN/OUT] Interface to be used by protocol

*

* @par Dependencies

* None

*

* @par Side Effects

* boot_sahara_init() will be called which calls the dispatch table's init()

* routine - this is intended to initialize any hardware that is required

* for the protocol to execute.

*

* @retval Boolean

*

* @sa None

*/

boolean boot_sahara_entry

(

struct boot_sahara_interface* sahara_interface

)

{

boolean status = TRUE;

sahara_if = sahara_interface;

// Validate interface and initialize Sahara protocol if not previously executed

status = boot_sahara_init();

if (status)

{

// Send hello packet

boot_sahara_handle_hello();

// Enter Sahara packet handler

boot_sahara_process_packets();

// Reset authentication information

sahara_auth_tbl = NULL;

sahara_auth_elf = FALSE;

sahara_auth_bin = FALSE;

}

return status;

}

调用函数boot_sahara_init初始化sahara协议,枚举usb com口及mass storage。

调用函数boot_sahara_handle_hello主动发送hello packet,

调用函数boot_sahara_process_packets处理其它cmd packets。

[cpp] view
plain copy

print?





/* ============================================================================

** Function : boot_sahara_init

** ============================================================================

*/

/*!

* @brief

* This function initializes the state for the Sahara protocol

*

* @details

* This function performs basic initialization in order to transfer an image.

* Based on the image type, the current image in shared data will be updated.

* This function also initializes the internal state machine and hardware

* driver.

*

* @param None

*

* @par Dependencies

* None

*

* @par Side Effects

* None

*

* @retval TRUE if initialization was successful; FALSE otherwise

*

* @sa None

*/

static boolean boot_sahara_init ( void )

{

boolean status = TRUE;

do

{

// Check parameters

if (sahara_if == NULL)

{

status = FALSE;

break;

}

if ((sahara_if->sahara_shared_data == NULL) ||

(sahara_if->dispatch_tbl == NULL))

{

status = FALSE;

break;

}

sahara_shared_data = sahara_if->sahara_shared_data;

sahara_dispatch_tbl = sahara_if->dispatch_tbl;

if (sahara_if->sahara_shared_data->cur_image == NULL)

{

status = FALSE;

break;

}

// Verify dispatch table

if ((sahara_dispatch_tbl->init == NULL) ||

(sahara_dispatch_tbl->shutdown == NULL) ||

(sahara_dispatch_tbl->poll == NULL) ||

(sahara_dispatch_tbl->rx_bulk == NULL) ||

(sahara_dispatch_tbl->tx_bulk == NULL) ||

(sahara_dispatch_tbl->shutdown == NULL) ||

(sahara_dispatch_tbl->get_max_packet_size == NULL) ||

(sahara_dispatch_tbl->reset == NULL) ||

(sahara_dispatch_tbl->valid_address_range == NULL) ||

(sahara_dispatch_tbl->exec_cmd == NULL) ||

(sahara_dispatch_tbl->get_max_raw_data_size == NULL) ||

(sahara_dispatch_tbl->auth_enabled == NULL) ||

(sahara_dispatch_tbl->memcpy == NULL) ||

(sahara_dispatch_tbl->memset == NULL) ||

(sahara_dispatch_tbl->get_bin_header_size == NULL) ||

(sahara_dispatch_tbl->get_bin_image_id == NULL) ||

(sahara_dispatch_tbl->get_bin_image_dest == NULL) ||

(sahara_dispatch_tbl->get_bin_image_size == NULL) ||

(sahara_dispatch_tbl->get_bin_code_size == NULL) ||

(sahara_dispatch_tbl->get_bin_cert_chain_size == NULL) ||

(sahara_dispatch_tbl->get_bin_signature_size == NULL) ||

(sahara_dispatch_tbl->get_hash_segment_buffer == NULL))

{

status = FALSE;

break;

}

// Determine if image should be authenticated

sahara_shared_data->is_secure = sahara_dispatch_tbl->auth_enabled();

sahara_auth_tbl = sahara_if->auth_tbl;

if (((sahara_auth_tbl == NULL) ||

(sahara_auth_tbl->authenticate == NULL)) &&

(sahara_if->sahara_mode != SAHARA_MODE_MEMORY_DEBUG))

{

status = FALSE;

break;

}

else if (sahara_shared_data->is_secure &&

(sahara_shared_data->expected_image_type == SAHARA_IMAGE_TYPE_ELF))

{

sahara_auth_elf = TRUE;

}

else if (sahara_shared_data->is_secure &&

(sahara_shared_data->expected_image_type == SAHARA_IMAGE_TYPE_BINARY))

{

sahara_auth_bin = TRUE;

}

sahara_mem_debug_tbl = sahara_if->mem_debug_tbl;

if (sahara_mem_debug_tbl == NULL)

{

sahara_mem_debug_enabled = FALSE;

}

else

{

if ((sahara_mem_debug_tbl->mem_debug_supported == NULL) ||

(sahara_mem_debug_tbl->mem_debug_init == NULL) ||

(sahara_mem_debug_tbl->mem_debug_verify_addr == NULL) ||

(sahara_mem_debug_tbl->mem_debug_table_addr == NULL) ||

(sahara_mem_debug_tbl->mem_debug_table_len == NULL) ||

(sahara_mem_debug_tbl->mem_debug_is_restricted_addr == NULL) ||

(sahara_mem_debug_tbl->mem_debug_copy_restricted == NULL))

{

status = FALSE;

break;

}

else

{

sahara_mem_debug_enabled = TRUE;

}

}

if (sahara_shared_data->expected_image_type == SAHARA_IMAGE_TYPE_BINARY)

{

sahara_binary_image_info =

(struct boot_sahara_binary_image_info*)sahara_shared_data->cur_image;

// Initialize binary image info

sahara_binary_image_info->image_id = 0;

// Check the binary image header has been initialized to a valid address

if (sahara_binary_image_info->header == NULL)

{

status = FALSE;

break;

}

sahara_dispatch_tbl->memset(sahara_binary_image_info->header,

0,

sahara_dispatch_tbl->get_bin_header_size());

}

else if (sahara_shared_data->expected_image_type == SAHARA_IMAGE_TYPE_ELF)

{

sahara_elf_image_info =

(struct boot_sahara_elf_image_info*)sahara_shared_data->cur_image;

// Check program headers buffer has been initialized to a valid address

if (sahara_elf_image_info->prog_headers == NULL)

{

status = FALSE;

break;

}

// Initialize ELF image info

sahara_elf_image_info->image_id = 0;

sahara_dispatch_tbl->memset(&(sahara_elf_image_info->elf_header),

0,

sizeof(Elf32_Ehdr));

sahara_elf_image_info->hash_table = NULL;

sahara_dispatch_tbl->memset(&(sahara_elf_image_info->shared_seg_index),

0,

sizeof(uint32));

sahara_dispatch_tbl->memset(&(sahara_elf_image_info->entry_address),

0,

sizeof(uint32));

/* zero initialize progressive_boot_block up to max possible

prog-header entries */

sahara_dispatch_tbl->memset((sahara_elf_image_info->prog_headers),

0,

sizeof(struct progressive_boot_block));

}

else if (sahara_if->sahara_mode != SAHARA_MODE_MEMORY_DEBUG)

{

// Image type not supported and not in memory debug mode

status = FALSE;

break;

}

// Initialize Sahara state information

sahara_if->sahara_shared_data->image_rx_complete = FALSE;

sahara_mode = (enum boot_sahara_mode) sahara_if->sahara_mode;

sahara_state = SAHARA_STATE_ENTRY;

sahara_done = FALSE;

// Initialize hardware driver interface

if(BULK_SUCCESS != sahara_dispatch_tbl->init())

{

status = FALSE;

break;

}

} while (0);

if(NULL != sahara_if)

{

if (status == FALSE)

{

// Report error in initialize to Sahara client

sahara_if->sahara_status = SAHARA_NAK_TARGET_INIT_FAILURE;

}

else

{

// Initialize sahara status

sahara_if->sahara_status = SAHARA_STATUS_SUCCESS;

}

}

return status;

}

调用sahara_dispatch_tbl->init函数指针, 即sbl1_sahara.c文件中的sbl_sahara_bulk_init()。

[cpp] view
plain copy

print?





struct qhsusb_dcd_dsc_device* qhsusb_fd_hdlc_init(void (*rx_callback)(struct qhsusb_urb* urb),

uint8* str_product,

void (*tx_callback)(struct qhsusb_urb* urb),

void (*enum_complete)(void),

void (*error_handler)(void),

qhsusb_transfer_mode transfer_mode)

#else

struct qhsusb_dcd_dsc_device* qhsusb_fd_hdlc_init(void (*rx_callback)(struct qhsusb_urb* urb),

uint8* str_product,

void (*tx_callback)(struct qhsusb_urb* urb),

void (*enum_complete)(void),

qhsusb_transfer_mode transfer_mode)

#endif

{

boolean hdlc_enum_already_exists = FALSE;

struct qhsusb_urb* urb;

qhsusb_transfer_mode_g = transfer_mode;

qhsusb_log(QHSUSB_FD_HDLC_INIT_LOG,0,0);

#ifndef FEATURE_SKIP_SERIAL_STR_UPDATE

qhsusb_fd_hdlc_update_pid_and_serial_number_string();

#endif

if ( NULL != str_product ) {

sw_device.strings[2].descriptor = (struct usb_desc_header*)(void*)str_product;

}

/* set up sw -> hw links */

#if defined(FEATURE_QHSUSB_HDLC_CDCACM)

hdlc_shutdown_in_progress = 0;

if ( 0 != hdlc_use_cdcacm ) {

sw_data_eps[0].descriptor = &hdlc_usb_config_cdcacm.ep_in;

sw_data_eps[1].descriptor = &hdlc_usb_config_cdcacm.ep_out;

sw_data_ifc.descriptor = &hdlc_usb_config_cdcacm.ifc_data;

sw_config.descriptor = &hdlc_usb_config_cdcacm.conf1;

sw_device.descriptor = &hdlc_usb_device_cdcacm;

sw_config.interfaces = &sw_cdc_control_ifc;

} else

#endif /* defined(FEATURE_QHSUSB_HDLC_CDCACM) */

{

if(QHSUSB_MODE__SER_MS == qhsusb_bulk_mode_g)

{

sw_data_eps[0].descriptor = &hdlc_usb_config_obex.ep_in;

sw_data_eps[1].descriptor = &hdlc_usb_config_obex.ep_out;

sw_data_ifc.descriptor = &hdlc_usb_config_obex.ifc_data;

sw_config.descriptor = &hdlc_usb_config_obex.conf1;

}

else if (QHSUSB_MODE__SER_ONLY == qhsusb_bulk_mode_g)

{

sw_data_ifc.next = NULL;

sw_data_eps[0].descriptor = &hdlc_usb_config_obex_only.ep_in;

sw_data_eps[1].descriptor = &hdlc_usb_config_obex_only.ep_out;

sw_data_ifc.descriptor = &hdlc_usb_config_obex_only.ifc_data;

sw_config.descriptor = &hdlc_usb_config_obex_only.conf1;

if(hdlc_usb_device_obex.idProduct == USB_PRODUCT_DIAG_MS )

{

/*For serial only mode, change the product ID to 0x9008*/

hdlc_usb_device_obex.idProduct = USB_PRODUCT_DIAG_ONLY;

hdlc_usb_device_obex.iSerialNumber = 0x0;

}

}

else if (QHSUSB_MODE__SER_ONLY__DL_MODE == qhsusb_bulk_mode_g)

{

sw_data_ifc.next = NULL;

sw_data_eps[0].descriptor = &hdlc_usb_config_obex_only.ep_in;

sw_data_eps[1].descriptor = &hdlc_usb_config_obex_only.ep_out;

sw_data_ifc.descriptor = &hdlc_usb_config_obex_only.ifc_data;

sw_config.descriptor = &hdlc_usb_config_obex_only.conf1;

if(hdlc_usb_device_obex.idProduct == USB_PRODUCT_DIAG_MS )

{

/*For serial only mode, change the product ID to 0x9008*/

hdlc_usb_device_obex.idProduct = USB_PRODUCT_DIAG_ONLY;

hdlc_usb_device_obex.iSerialNumber = 0x0;

}

}

sw_device.descriptor = &hdlc_usb_device_obex;

sw_config.interfaces = &sw_data_ifc;

#ifdef FEATURE_QHSUSB_MS

if( QHSUSB_MODE__SER_MS == qhsusb_bulk_mode_g )

{

/*Initialize the MS stack when you are in download mode only*/

qhsusb_fd_ms_init();

}

#endif /* FEATURE_QHSUSB_MS */

}

// Set enum flag for RS bit to be turned ON in qhsusb_dci_init();

qhsusb_dci_set_enum_flag(TRUE);

qhsusb_dcd_init(&sw_device);

user_rx_callback = rx_callback;

if (tx_callback != NULL)

{

user_tx_callback = tx_callback;

}

if (enum_complete != NULL)

{

user_enum_complete = enum_complete;

}

#ifdef FEATURE_QHSUSB_SAHARA_DOWNLOAD_PIPO

if( error_handler !=NULL)

{

user_error_handler = error_handler;

}

#endif

hdlc_enum_already_exists = dci_skip_enumeration(sw_device.core_id);

/* Data buffers & URB's */

/* tx */

urb = &hdlc_tx_urb;

urb->usb_device = &sw_device;

urb->endpoint_address = sw_data_eps[0].descriptor->bEndpointAddress;

urb->transfer_buffer_ptr = hdlc_tx_buffer;

urb->transfer_length = 0;

urb->transfer_status = 0;

urb->send_zlp = TRUE;

urb->complete_callback = hdlc_tx_callback;

urb->is_zero_address_chain_required = FALSE;

if (transfer_mode == FD_CLIENT_SUPPLIED_BUFFER_MODE) /* Client Supplied Buffer Mode */

{

/* rx */

urb = &hdlc_rx_urb;

urb->usb_device = &sw_device;

urb->endpoint_address = sw_data_eps[1].descriptor->bEndpointAddress;

urb->transfer_buffer_ptr = NULL; /* to be filled by al layer */

urb->transfer_length = 0; /* to be filled by al layer */

urb->send_zlp = FALSE;

urb->complete_callback = hdlc_rx_callback;

urb->actual_length = 0;

/*Initially set the is_zero_address_chain_required to FALSE*/

urb->is_zero_address_chain_required = FALSE;

}

else /* Internal Buffer Mode */

{

uint8 i = 0;

for (i = 0; i < 2; i++) {

urb = &hdlc_rx_urb_fixed[i];

urb->usb_device = &sw_device;

urb->endpoint_address = sw_data_eps[1].descriptor->bEndpointAddress;

urb->transfer_buffer_ptr = hdlc_rx_buffer_fixed[i];

urb->transfer_length = RX_BUF_SIZE_FIXED;

urb->send_zlp = FALSE;

urb->complete_callback = hdlc_rx_callback_int_buf_mode;

urb->actual_length = 0;

/*Initially set the is_zero_address_chain_required to FALSE*/

urb->is_zero_address_chain_required = FALSE;

}

}

/* cdc_notify_urb */

#if defined(FEATURE_QHSUSB_HDLC_CDCACM)

if ( 0 != hdlc_use_cdcacm ) {

urb = &cdc_notify_urb;

urb->usb_device = &sw_device;

urb->endpoint_address = hdlc_usb_config_cdcacm.ep_notify.bEndpointAddress;

urb->transfer_length = 0;

urb->complete_callback = NULL;

}

#endif /* defined(FEATURE_QHSUSB_HDLC_CDCACM) */

#ifndef FEATURE_QHSUSB_PBL

if (hdlc_enum_already_exists)

{

/**

* We got here without reconnect. enumeration already

* completed. Simulate connection and SET_CONFIG

*/

qhsusb_dcd_port_status_changed(&sw_device); /* attachment, speed... */

sw_device.address = 1; /* don't care, just not 0 */

qhsusb_dci_cancel_transfer_wo_dqh_dtd(sw_device.core_id, 1, QHSUSB_EP_DIR_RX);

qhsusb_dci_cancel_transfer_wo_dqh_dtd(sw_device.core_id, 1, QHSUSB_EP_DIR_TX);

qhsusb_dci_cancel_transfer_wo_dqh_dtd(sw_device.core_id, 2, QHSUSB_EP_DIR_RX);

qhsusb_dci_cancel_transfer_wo_dqh_dtd(sw_device.core_id, 2, QHSUSB_EP_DIR_TX);

qhsusb_dcd_set_config(&sw_device, 1);

if (transfer_mode == FD_USB_INTERNAL_BUFFER_MODE)

{

hdlc_init_rx_int_buf_mode(urb->usb_device);

}

}

#endif /* !FEATURE_QHSUSB_PBL */

return &sw_device;

}

sbl_sahara_bulk_init函数最终调用到qhsusb_fd_ms.c文件中的函数:qhsusb_fd_ms_init , 

整个初始化过程结束后完成com端口及mass storage枚举过程。



还有!!! 坑爹的高通,以前不提供生产用的软件下载工具,都得手机厂商自己开发。

高通思想终于改变了,QRD加入后,为手机厂商提供支持多路的软件升级工具:QMSCT 。

虽然设置比较繁琐,不管怎么样,总算可用。上张图吧!



QFIL和QMSCT是使用紧急下载模式,由PBL及下面firehose
prog代码完成下载过程。

boot_images/core/storage/tools/deviceprogrammer

五、Crash ramdump

  哎,这篇被我写得又长又臭啦。算了,这节就不详细写了。

  高通平台开放,本身也不稳定,因此做出的手机系统很多都不稳定。因此系统crash发生时,抓取crash现场就非常重要。

  这里简单说一下,高通平台抓取系统crash现场的几种方法:

  1、 通过QPST提供的 Memory Debug Application工具,当crash发生时,手机通过usb连接到PC, 然后用这个工具将crash现场的ram dump到电脑。

   显然,这种方法是最可靠的,但它有自身的局限性:不可能每次crash发生时,测试人员或者试用人员、研发人员都刚好在pc旁边。

  2、 高通平台sbl1提供将crash现场dump到sdcard的功能,如下代码。 这种方法的局性限是:

   现在高端手机,都没有外置sdcard的配置的,而内置sdcard又使用fuse ext4文件系统,而sbl1只支持fat文件系统。 

   因此,这种不配置外置sdcard的手机,这种方法根本不可行。

[cpp] view
plain copy

print?





/*==========================================================================

List of SBL1 procedures to execute prior to dload entry

===========================================================================*/

boot_procedure_func_type sbl1_pre_dload_procs[] =

{

/*-----------------------------------------------------------------------

* Initialization functions for dload. This has to be the first function

* called before Dload entry

*----------------------------------------------------------------------*/

boot_init_for_dload,

/*-----------------------------------------------------------------------

* Setup clocks for ram dump

*----------------------------------------------------------------------*/

sbl1_hw_dload_init,

/*-----------------------------------------------------------------------

* Ram dump to eMMC raw partition, this function will reset device

* after successful dump collection if cookie is set

*----------------------------------------------------------------------*/

(boot_procedure_func_type) boot_ram_dump_to_raw_parition,

#ifdef FEATURE_BOOT_RAMDUMPS_TO_SD_CARD

/*----------------------------------------------------------------------

* Take the Ramdumps to SD card if cookie file is

* present in SD card

*---------------------------------------------------------------------*/

boot_ram_dumps_to_sd_card,

#endif /*FEATURE_BOOT_RAMDUMPS_TO_SD_CARD*/

/*-----------------------------------------------------------------------

* NULL pointer indicates the end of the list

*-----------------------------------------------------------------------*/

NULL

};

  3、 campact ramdump:这是QRD提出来的思路,即:仅dump一部分比较有用的ram到一个专门为crash分配的emmc分区。

system crash 的主要发生的,ap核的 kernel及service,rpm , modem 等核,而上层Java代码不容易导致system
crash。

 而现在手机的内置越来越大,1G、2G甚至3G,整个ram都dump到一个特定分区,就浪费emmc空间了。

 因此,compact ramdump就是将一部分关键的ram dump到专门为crash分配的emmc分区。 这样就不依赖于sdcard,也不依赖于usb。而且也不浪费emmc空间。

高通很多平台都没实现这功能,比如,msm8916, msm8974等,实现思路可以参考QRD8x25平台。

六、其它

sbl1_hw_init ()

boot_smem_store_pon_status()

sbl1_hw_init_secondary()

=========> pmic 初始化,电池低电时利用内部pmic进行预充电,power key 配置,获取、保存开机原因等。 见:pm_sbl_boot.c

sbl1_tlmm_init() //gpio 初始化

sbl初始化gpio的初始状态代码如下:core/systemdrivers/tlmm/config/msm8916/TLMMChipset.xml

sbl1_efs_handle_cookies // efs backup/restore

boot_populate_ram_partition_table

====> 解析iram , imem , system ram 的起始地址,大小等, 并保存到smem: SMEM_USABLE_RAM_PARTITION_TABLE ,传递给lk和kernel。

见: boot_ram_partition.c , 这里重点看看ram的情况吧.

[cpp] view
plain copy

print?





/*===========================================================================

** Function : sbl1_update_ddr_info

** ==========================================================================

*/

/*!

*

* @brief

* This funcion will get ddr information from ddr driver and put it in

* sbl_shared_data.

*

* @param[in] bl_shared_data Pointer to shared data

*

* @par Dependencies

* Must be called after sbl1_ddr_init

*

* @retval

* None

*

* @par Side Effects

* None

*

*/

static void sbl1_update_ddr_info(bl_shared_data_type *bl_shared_data)

{

static sbl_if_shared_ddr_device_info_type ddr_info;

ddr_size_info ddr_available = boot_ddr_get_size();

ddr_size_partition ddr_partition_info = boot_ddr_get_partition();

boot_share_extended_ddr_info(&ddr_info, &ddr_available, &ddr_partition_info);

bl_shared_data->sbl_shared_data->ddr_shared_info = &ddr_info;

boot_set_ddr_info(bl_shared_data);

}

从ddr driver层获取到ddr 类型、大小,cs等信息,保存到sbl_shared_data->ddr_shared_info, 同时保存到sbl全局变量:boot_ddr_size_info

[cpp] view
plain copy

print?





/*===========================================================================

** Function : add_system_ram_partitions

** ==========================================================================

*/

/*!

*

* @brief

* Function adds all the DDR interfaces to ram partition table.

* Each DDR interface will be added as a single entry in the table.

* Partition category will be RAM_PARTITION_SDRAM for all DDR entries.

*

* @param[in] usable_ram_part_tbl_ptr Pointer to the ram partition table that

* should be populated

*

* @par Dependencies

* None

*

* @retval

* ram_partition_return_type

* RAM_PART_SUCCESS - if function is successful.

* RAM_PART_TABLE_FULL_ERR - if table is full or not enough space in

* the table

* RAM_PART_CATEGORY_NOT_EXIST_ERR - if unable to populate certain DDR information

*

* @par Side Effects

* None

*/

static ram_partition_return_type add_system_ram_partitions

(

usable_ram_part_table_t usable_ram_part_tbl_ptr

)

{

ram_part_entry_t ram_part_entry_ptr = NULL;

sbl_if_shared_ddr_info_type *ddr_info = NULL;

sbl_if_shared_extended_ddr_info_type *ddr_extended_info = NULL;

uint32 partition_index = 0;

ram_partition_return_type result = RAM_PART_SUCCESS;

sbl_if_shared_ddr_device_info_type *ddr_shared_info = boot_get_ddr_info();

/*ram_part_entry_ptr points to first empty slot in the table*/

ram_part_entry_ptr =

&usable_ram_part_tbl_ptr->

ram_part_entry[usable_ram_part_tbl_ptr->num_partitions];

/*Loop through ddr_info and add all DDR interfaces into the table*/

for(; partition_index < ddr_shared_info->noofddr &&

usable_ram_part_tbl_ptr->num_partitions < RAM_NUM_PART_ENTRIES;

partition_index++)

{

ddr_info = &ddr_shared_info->ddr_info[partition_index];

ram_part_entry_ptr->partition_category = RAM_PARTITION_SDRAM;

ram_part_entry_ptr->start_address = ddr_info->cs_addr;

ram_part_entry_ptr->length = ddr_info->ramsize << CONVERT_TO_BYTE_SHIFT;

ram_part_entry_ptr->partition_attribute = RAM_PARTITION_READWRITE;

ram_part_entry_ptr->partition_domain = RAM_PARTITION_DEFAULT_DOMAIN;

ram_part_entry_ptr->partition_type = RAM_PARTITION_SYS_MEMORY;

/*Add the extended ddr information to current ram partition entry*/

if(ddr_shared_info->ddr_partition_info != NULL)

{

ddr_extended_info = &ddr_shared_info->ddr_partition_info[partition_index];

/*Make sure the base address of ddr extended info matches the current ddr base address*/

if (ddr_extended_info->sdram_addr != ram_part_entry_ptr->start_address)

{

result = RAM_PART_CATEGORY_NOT_EXIST_ERR;

break;

}

ram_part_entry_ptr->num_partitions = ddr_extended_info->num_partitions;

}

ram_part_entry_ptr++;

usable_ram_part_tbl_ptr->num_partitions++;

}

return result;

}

添加如下打印log语句在代码ddr_info = &ddr_shared_info->ddr_info[partition_index];后面,
snprintf(message, 256,

"noofddr %d , cs_addr %d, ramsize %d", ddr_shared_info->noofddr, ddr_info->cs_addr, ddr_info->ramsize);

boot_log_message(message);

可以看到如下ddr info log信息:

B - 376400 - noofddr 2 , cs_addr 80000000, ramsize 1024

B - 376431 - noofddr 2 , cs_addr c0000000, ramsize 1024

七、sbl1 常用的tools介绍

sbl1常用的tools及源码在如下目录:

boot_images/core/storage/tools/

1、 fat32 udisk 生成工具:

boot_images/core/storage/tools/fattool ,

Python fatgen.py –fat32 --name=udisk.bin --size=2048 # Generate a 2GB
FAT32 Container.

python fatadd.py --name=udisk.bin --from=rdcookie.txt ----add rdcookie.txt into udisk.bin ,for test

这两个py比原来7k平台可执行文件cpfatfs功能更强了,cpfatfs只支持fat16

2、QPST下载工具(shahara):emmc programmer

:/boot_images/core/storage/tools/emmcbld/MPRG8974.mbn

3、 T32 Jtag下载工具

boot_images/core/storage/tools/jsdcc/mjsdload.cmm 与jsdcc.elf

4、分区相关工具

boot_images/core/storage/tools/ptool/

ptool.py //分区生成工具 partition =========> rawprogram0.xml

Python ptool.py –x partition.xml:

msp.py //ubuntu使用:根据 rawprogram0.xml进行升级软件工具

singleimage.py  //根据singleimage_partition_8974.xml生成single boot image: 8974_msimage.mbn

python singleimage.py -x singleimage_partition_8974.xml

lsusb.py // ls usb

dd.py // dd command

checksparse.py //sparse system/cache/userdata image
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bootloader sbl qcom