续:高通 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
/*============================================================================= ** 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() */
<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() */
/*=========================================================================== ** 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); }
<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 ,
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,
<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
</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; } }
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; }
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); } }
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; }使能普通下载模式。
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
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() */
/*=========================================================================== ** 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。
/* 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, };
/* ============================================================================ ** 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。
/* ============================================================================ ** 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()。
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; }
整个初始化过程结束后完成com端口及mass storage枚举过程。
还有!!! 坑爹的高通,以前不提供生产用的软件下载工具,都得手机厂商自己开发。
高通思想终于改变了,QRD加入后,为手机厂商提供支持多路的软件升级工具:QMSCT 。
虽然设置比较繁琐,不管怎么样,总算可用。上张图吧!
哎,这篇被我写得又长又臭啦。算了,这节就不详细写了。
高通平台开放,本身也不稳定,因此做出的手机系统很多都不稳定。因此系统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的手机,这种方法根本不可行。
/*========================================================================== 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_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的情况吧.
/*=========================================================================== ** 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
/*=========================================================================== ** 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,可以看到如下ddr info log信息:
B - 376400 - noofddr 2 , cs_addr 80000000, ramsize 1024
B - 376431 - noofddr 2 , cs_addr c0000000, ramsize 1024
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