活动介绍
file-type

HTML与CSS:BFC、IFC理解及清除浮动、盒模型和选择器优先级

MD文件

下载需积分: 9 | 52KB | 更新于2024-08-05 | 113 浏览量 | 0 下载量 举报 收藏
download 立即下载
"HTML & CSS 知识点概览" 在HTML和CSS的世界里,理解和掌握BFC(Block Formatting Context)和IFC(Inline Formatting Context)是构建页面布局的基础。BFC和IFC定义了元素如何在页面上排列和交互。 **BFC(块级格式化上下文)** 是一种布局概念,主要涉及以下规则: 1. BFC中的子元素沿垂直方向堆叠,间距由它们的margin决定。 2. 同一BFC内的相邻盒的margin会发生层叠。 3. 元素的左边与包含它的BFC的左边接触,即使有浮动元素也不会受影响。 4. BFC区域不会与浮动元素重叠。 5. BFC是一个独立的容器,其内部元素不会影响外部元素,反之亦然。 6. 计算BFC高度时,浮动元素也会被纳入考虑。 触发BFC的条件包括: 1. 根元素 2. 浮动元素(float属性不为none) 3. 绝对或固定定位元素(position属性为absolute或fixed) 4. 显示模式为inline-block、table-cell、table-caption或flex的元素 5. overflow属性不为visible **IFC(行级格式化上下文)** 规定了元素在水平方向上的布局,主要包括: 1. 内部元素水平排列,当一行无法容纳时自动换行。 2. IFC的高度由其中最高的元素决定。 **CSS 清除浮动** 是解决“浮动元素导致的父元素高度塌陷”问题的关键。常见方法包括: 1. 父元素设定固定高度并手动扩展。 2. 在浮动元素后面添加空标签,并设置`clear:both`。 3. 父元素设置`overflow:hidden`。 4. 使用伪类`:before`和`:after`及`zoom:1`来创建新的BFC(双伪元素法)。 **盒模型** 描述了元素的尺寸计算,分为两种: 1. IE盒模型(怪异盒模型,border-box):盒子宽度包括content、padding和border。 2. W3C盒模型(标准盒模型,content-box):盒子宽度仅由content决定。 **CSS选择器优先级** 规定了不同类型的CSS选择器的权重: 1. `!important`声明 > 内联样式 > ID选择器 > 类/属性/伪类 > 元素/关系选择器。 **CSS三列布局** 通常可以实现各种布局效果,如左右两列固定宽度,中间列自适应。通过`float`、`display`属性等技术可以轻松实现这一布局。 例如,使用`float`实现这种布局,左侧和右侧的div分别设置`float:left`和`float:right`,中间的div默认占据剩余空间。如果需要更复杂的布局,还可以使用Flexbox或Grid布局。

相关推荐

filetype

ibintl-full/include -DEXIT_WITHOUT_RECYCLING_RESOURCES -DESP32_SUPPORT -DT23x_MMC_INSMOD_MANUAL -DFACTORY_MODE_NOT_AMS -I/home/linzihao/Code/onvif1/NVMP/nvmp/staging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/include -I/home/linzihao/Code/onvif1/NVMP/nvmp/staging_dir/target-mips-openwrt-linux-uclibc-c200v5/include -I/home/linzihao/Code/onvif1/NVMP/nvmp/../sdk/soc/T23/toolchain/mips-gcc540-glibc222-64bit-r3.3.0.smaller/mips-linux-gnu/libc/uclibc/usr/include -I/home/linzihao/Code/onvif1/NVMP/nvmp/staging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/lib/libiconv-full/include -I/home/linzihao/Code/onvif1/NVMP/nvmp/staging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/lib/libintl-full/include -Wall -Werror -ffunction-sections -fdata-sections -c -o main.o main.c mips-linux-uclibc-gnu-gcc build_dir/target-mips-openwrt-linux-uclibc-c200v5/main/main.o "mips-linux-uclibc-gnu-gcc -o main main.o libraries/mpp/isp_data_model/image_profile_model.o libraries/mpp/isp_data_model/isp_data_model.o libraries/mpp/isp_data_model/audio_profile_model.o libraries/mpp/fv_focus_test/fv_focus_test.o libraries/mpp/fv_focus_test/fv_data_model.o libraries/avts/hub_storage/hub_storage.o libraries/avts/hub_storage/hub_storage_debug.o libraries/avts/rtspd/session.o libraries/avts/rtspd/rtspd.o libraries/avts/avts/shmem.o libraries/avts/avts/storage.o libraries/avts/avts/partition_ops.o libraries/avts/avts/event_index_block.o libraries/avts/avts/ring_object.o libraries/avts/avts/mp4_mux.o libraries/avts/avts/playback.o libraries/avts/avts/playback_thread.o libraries/avts/avts/stg_event.o libraries/avts/avts/disk.o libraries/avts/avts/entry_cache.o libraries/avts/avts/stg_disk.o libraries/avts/avts/subscriber_manage.o libraries/avts/avts/event_table.o libraries/avts/avts/snapshot_index.o libraries/avts/avts/msg_push.o libraries/avts/avts/ds.o libraries/avts/avts/avdm.o libraries/avts/avts/sd_snapshot.o libraries/avts/avts/mp4_demux.o libraries/avts/avts/stg_utils.o libraries/avts/avts/playback_event.o libraries/avts/avts/sys_info.o libraries/avts/avts/utils.o libraries/avts/avts/file_ops.o libraries/avts/avts/record.o libraries/avts/avts/crossline.o libraries/avts/avts/stg_api.o libraries/avts/avts/mp4_handler.o libraries/avts/avts/avts_cmd.o libraries/avts/avts/disk_list.o libraries/avts/avts/common_api.o libraries/avts/avts/hd_manage.o libraries/avts/avts/stg_dbg.o libraries/avts/avts/index_memory.o libraries/avts/avts/file.o libraries/avts/avts/face_enhance.o libraries/avts/avts/storage_data_model.o libraries/avts/avts/index_binary.o libraries/avts/avts/signal_handler.o libraries/avts/avts/disk_exception.o libraries/avts/avts/reupload_index.o libraries/avts/avts/tp_disk_format.o libraries/avts/avts/mp4_tpwfile.o libraries/avts/avts/index_file_ops.o libraries/avts/avts/data_partition.o libraries/avts/avts/interface.o libraries/avts/avts/avts.o libraries/avts/avts/event.o libraries/avts/avts/calendar.o libraries/avts/avts/binary_index_file.o libraries/avts/avts/read_helper.o libraries/avts/avts/playback_client.o libraries/avts/p2p/stun.o libraries/avts/p2p/fp_ttl_probe.o libraries/avts/p2p/session.o libraries/avts/p2p/video_share.o libraries/avts/p2p/get_nat.o libraries/avts/p2p/utils.o libraries/avts/p2p/p2pd.o libraries/avts/p2p/p2p_nat8.o libraries/avts/p2p/fp_ttl.o libraries/avts/p2p/epoll_event.o libraries/avts/http_server/httpserversession.o libraries/avts/http_server/http_p2p.o libraries/avts/http_server/httpserver.o libraries/avts/http_server/http_data_model.o libraries/avts/http_server/flow_ctr.o libraries/avts/http_server/tspackage.o libraries/avts/http_server/client_info.o libraries/avts/http_server/tsunpack.o libraries/avts/http_server/tsdemux.o libraries/avts/http_server/httpcommon.o libraries/avts/http_server/es_mp3_to_ts.o libraries/avts/http_server/ts_pack.o libraries/avts/http_server/stream_transmit.o libraries/avts/http_server/libtspack.o libraries/avts/http_server/http_server_module.o libraries/avts/tapo_care/media.o libraries/avts/tapo_care/tapo_care_debug.o libraries/avts/tapo_care/cloud_token.o libraries/avts/tapo_care/tapo_care.o libraries/avts/tapo_care/reupload.o libraries/avts/tapo_care/http_common.o libraries/avts/relay/session.o libraries/avts/relay/relay.o libraries/avts/relay/cookie.o libraries/avts/relay/http_relay.o libraries/avts/rtsp_server/TPFECCodec.o libraries/avts/rtsp_server/rtspcommon.o libraries/avts/rtsp_server/tpudpserver.o libraries/avts/rtsp_server/client_info.o libraries/avts/rtsp_server/data_src.o libraries/avts/rtsp_server/rtspserver.o libraries/avts/rtsp_server/RS_fec.o libraries/avts/rtsp_server/rtpcommon.o libraries/avts/rtsp_server/rtp4server.o libraries/avts/rtsp_server/rtspserversession.o libraries/avts/rtsp_server/rtsp_server_module.o libraries/avts/rtsp_server/rtsp_data_model.o libraries/avts/rtsp_server/authmanager.o libraries/avts/rtsp_server/srtp_session.o libraries/avts/rtsp_server/rtspdsocket_client.o libraries/avts/rtsp_server/rtppackage.o libraries/avts/rtsp_server/sdp4server.o libraries/avts/rtsp_server/authentication.o libraries/avts/rtsp_server/networkutil.o libraries/avts/rtsp_server/srtp.o libraries/cap/video/video_data_model.o libraries/cap/video/roi_data_model.o libraries/cap/record_plan/record_plan_ds.o libraries/cap/record_plan/record_plan.o libraries/cap/detection_region/dr.o libraries/cap/detection_region/dr_data_model.o libraries/cap/hsr/hsr.o libraries/cap/cap/cap.o libraries/cap/md_alarm/md_alarm.o libraries/cap/md_alarm/md_pir.o libraries/cap/osd/osd_data_model.o libraries/cap/osd/osd.o libraries/cap/osd/tpcam_osd_control.o libraries/cap/sd_card/sd_card.o libraries/cap/bcd_alarm/bcd_alarm.o libraries/cap/ptz/limit.o libraries/cap/ptz/home.o libraries/cap/ptz/ubus.o libraries/cap/ptz/module.o libraries/cap/ptz/params_init.o libraries/cap/ptz/tp_ptz.o libraries/cap/ptz/tour.o libraries/cap/ptz/ds_target_track.o libraries/cap/ptz/ptz.o libraries/cap/ptz/ds_tour.o libraries/cap/ptz/patrol.o libraries/cap/ptz/debug.o libraries/cap/ptz/ds_patrol.o libraries/cap/ptz/target_track.o libraries/cap/ptz/ds_lens_mask.o libraries/cap/ptz/preset.o libraries/cap/ptz/callback.o libraries/cap/ptz/ds_park.o libraries/cap/ptz/utils.o libraries/cap/ptz/ds_preset.o libraries/cap/ptz/basic.o libraries/cap/ptz/plan.o libraries/cap/ptz/ds_scan.o libraries/cap/ptz/ptz_data_model.o libraries/cap/ptz/scan.o libraries/cap/ptz/ds_basic.o libraries/cap/ptz/ds_home.o libraries/cap/ptz/entry.o libraries/cap/ptz/ds_plan.o libraries/cap/ptz/park.o libraries/cap/ptz/lens_mask.o libraries/cap/ptz/uci_image_flip.o libraries/cap/ptz/ds_limit.o libraries/cap/ptz/coor_transform.o libraries/cap/led_rule/led_rule.o libraries/cap/led_rule/led.o libraries/cap/od_alarm/od_alarm.o libraries/cap/msg_alarm/msg_alarm.o libraries/cap/msg_alarm/light_control.o libraries/cap/msg_alarm/usr_def_audio.o libraries/cap/cover/cover_data_model.o libraries/cap/cover/cover.o libraries/cap/image/image_cmd.o libraries/cap/image/image_data_model.o libraries/cap/image/image_utils.o libraries/cap/image/image.o libraries/cap/detection_common/detection_common.o libraries/cap/speaker/audio_stream.o libraries/cap/speaker/speaker_data_model.o libraries/cap/speaker/speaker.o libraries/cap/speaker/language_data_model.o libraries/cap/dn_switch/dn_switch.o libraries/cap/dn_switch/dn_switch_buff.o libraries/cap/dn_switch/dn_switch_cmd.o libraries/cap/dn_switch/dn_switch_process.o libraries/nsd/openapi/fast_openapi_cloud.o libraries/nsd/openapi/fast_openapi_motion_detection.o libraries/nsd/openapi/fast_openapi_alert.o libraries/nsd/openapi/fast_openapi_sd_card.o libraries/nsd/openapi/fast_openapi_system.o libraries/nsd/openapi/fast_openapi.o libraries/nsd/openapi/fast_openapi_ptz.o libraries/nsd/openapi/fast_openapi_playback.o libraries/nsd/openapi/fast_openapi_msg_push.o libraries/nsd/openapi/fast_openapi_audio.o libraries/nsd/openapi/openapi_https_server.o libraries/nsd/openapi/fast_openapi_date_time.o libraries/nsd/openapi/openapi.o libraries/nsd/openapi/openapi_data_model.o libraries/nsd/openapi/fast_openapi_wireless.o libraries/nsd/openapi/fast_openapi_account.o libraries/nsd/openapi/fast_openapi_privacy_mode.o libraries/nsd/openapi/fast_openapi_record.o libraries/nsd/openapi/fast_openapi_dayNight_mode.o libraries/nsd/openapi/fast_openapi_video.o libraries/nsd/sntpc/sntpc.o libraries/nsd/hub_manage/hub_manage.o libraries/nsd/hub_manage/hub_manage_data_model.o libraries/nsd/hub_manage/hub_manage_http_client.o libraries/nsd/hub_manage/hub_manage_login.o libraries/nsd/hub_manage/hub_manage_request_handle.o libraries/nsd/hub_manage/ai_enhance.o libraries/nsd/hub_manage/hub_man_debug.o libraries/nsd/wirelesstool/wirelesstool_business.o libraries/nsd/wirelesstool/wirelesstool_config.o libraries/nsd/tdp_common/tdp_common.o libraries/nsd/httpd/http_auth.o libraries/nsd/httpd/data_model.o libraries/nsd/httpd/http_login_err.o libraries/nsd/httpd/httpd.o libraries/nsd/httpd/http_parser.o libraries/nsd/httpd/http_special_request.o libraries/nsd/httpd/http_log.o libraries/nsd/httpd/media_encrypt.o libraries/nsd/httpd/http_utils.o libraries/nsd/tdpd/tp_tlv.o libraries/nsd/tdpd/tdpd.o libraries/nsd/dhcps/dhcps.o libraries/nsd/cloud_iot/cloud_iot_data_model.o libraries/nsd/cloud_iot/cvm_get_ca.o libraries/nsd/cloud_iot/log_upload.o libraries/nsd/cloud_iot/download_thread.o libraries/nsd/cloud_iot/base64.o libraries/nsd/cloud_iot/device_telemetry.o libraries/nsd/cloud_iot/usr_request.o libraries/nsd/cloud_iot/dst.o libraries/nsd/cloud_iot/openapi_bind.o libraries/nsd/cloud_iot/cloud_iot_config.o libraries/nsd/cloud_iot/mqtt_client.o libraries/nsd/cloud_iot/json-api.o libraries/nsd/cloud_iot/cloud_iot_common.o libraries/nsd/cloud_iot/cloud_iot_ipc.o libraries/nsd/cloud_iot/cloud_iot.o libraries/nsd/cloud_iot/mqtt_packet.o libraries/nsd/cloud_iot/error_handler.o libraries/nsd/cloud_iot/msgPush.o libraries/nsd/cloud_iot/http_client.o libraries/nsd/cloud_iot/iot_encrypt.o libraries/nsd/cloud_iot/http_common.o libraries/nsd/cloud_iot/device_token.o libraries/nsd/mactool/mactool_cmd.o libraries/nsd/mactool/mactool_flash.o libraries/nsd/mactool/mactool_business.o libraries/nsd/nsd/nsd.o libraries/nsd/onvif/data_model.o libraries/nsd/onvif/tan_passthrough.o libraries/nsd/onvif/tptz_passthrough.o libraries/nsd/onvif/soap_common.o libraries/nsd/onvif/soap_parse.o libraries/nsd/onvif/soap_tptz.o libraries/nsd/onvif/md_active_cells.o libraries/nsd/onvif/soap_auth.o libraries/nsd/onvif/onvif_srv.o libraries/nsd/onvif/soap_tev.o libraries/nsd/onvif/onvif.o libraries/nsd/onvif/soap_event.o libraries/nsd/onvif/soap_pack.o libraries/nsd/onvif/soap_tr2.o libraries/nsd/onvif/soap_timg.o libraries/nsd/onvif/onvif_passthrough.o libraries/nsd/onvif/onvif_common.o libraries/nsd/onvif/soap_trt.o libraries/nsd/onvif/soap_tds.o libraries/nsd/onvif/tr2_passthrough.o libraries/nsd/onvif/imaging.o libraries/nsd/onvif/tds_passthrough.o libraries/nsd/onvif/soap_tan.o libraries/nsd/onvif/soap.o libraries/nsd/onvif/soap_wsdd.o libraries/nsd/onvif/packbits.o libraries/nsd/onvif/onvif_discv.o libraries/nsd/onvif/soap_global.o libraries/nsd/onvif/trt_passthrough.o libraries/nsd/nifc/stc_ip.o libraries/nsd/nifc/system.o libraries/nsd/nifc/nifc_data_model.o libraries/nsd/nifc/nifc.o libraries/nsd/nifc/cmd.o libraries/nsd/nifc/dhcpc.o libraries/nsd/system/system.o libraries/nsd/system/timing_reboot_data_model.o libraries/nsd/system/auto_upgrade_data_model.o libraries/nsd/system/app_component_data_model.o libraries/nsd/system/recover_man.o libraries/nsd/system/sysprepare.o libraries/nsd/system/sys_reset.o libraries/nsd/ffs/ffs_dss_operation_compute_configuration_data.o libraries/nsd/ffs/ffs_dss_operation_post_wifi_scan_data.o libraries/nsd/ffs/ffs_dss_wifi_security_protocol.o libraries/nsd/ffs/ffs_ubus_api.o libraries/nsd/ffs/ffs_convert_registration_state.o libraries/nsd/ffs/ffs_wifi_context.o libraries/nsd/ffs/ffs_linked_list.o libraries/nsd/ffs/ffs_dss_wifi_connection_state.o libraries/nsd/ffs/ffs_convert_json_value.o libraries/nsd/ffs/ffs_dss_operation_start_pin_based_setup.o libraries/nsd/ffs/ffs_dss_wifi_connection_attempt.o libraries/nsd/ffs/ffs_dss_wifi_connection_details.o libraries/nsd/ffs/ffs_dss_device_details.o libraries/nsd/ffs/ffs_wifi_provisionee_setup_network.o libraries/nsd/ffs/ffs_convert_registration_details.o libraries/nsd/ffs/ffs_wifi_provisionee_task.o libraries/nsd/ffs/ffs_convert_device_details.o libraries/nsd/ffs/ffs_dss_start_provisioning_session_request.o libraries/nsd/ffs/ffs_convert_wifi_credentials.o libraries/nsd/ffs/ffs_linux_main.o libraries/nsd/ffs/ffs_linux_crypto_common.o libraries/nsd/ffs/ffs_dss_operation_start_provisioning_session.o libraries/nsd/ffs/ffs_dss_start_pin_based_setup_request.o libraries/nsd/ffs/ffs_raspbian_wpa_supplicant.o libraries/nsd/ffs/ffs_dss_start_pin_based_setup_response.o libraries/nsd/ffs/ffs_linux_http_client.o libraries/nsd/ffs/ffs_linux_logging.o libraries/nsd/ffs/ffs_iso8601.o libraries/nsd/ffs/ffs_dss_client.o libraries/nsd/ffs/ffs_shell.o libraries/nsd/ffs/ffs_raspbian_iwlist.o libraries/nsd/ffs/ffs_linux_wifi.o libraries/nsd/ffs/ffs_dss_configuration.o libraries/nsd/ffs/ffs_base64.o libraries/nsd/ffs/ffs_dss_post_wifi_scan_data_response.o libraries/nsd/ffs/ffs_dss_report_request.o libraries/nsd/ffs/ffs_wifi_scan_list.o libraries/nsd/ffs/ffs_wifi.o libraries/nsd/ffs/ffs_wifi_provisionee_encoded_setup_network.o libraries/nsd/ffs/ffs_dss_wifi_credentials.o libraries/nsd/ffs/ffs_base85.o libraries/nsd/ffs/ffs_dss_error_details.o libraries/nsd/ffs/ffs_wifi_manager.o libraries/nsd/ffs/ffs_dss_wifi_scan_result.o libraries/nsd/ffs/ffs_dss_get_wifi_credentials_request.o libraries/nsd/ffs/ffs_dss_report_response.o libraries/nsd/ffs/ffs_dss_compute_configuration_data_response.o libraries/nsd/ffs/ffs_linux_crypto.o libraries/nsd/ffs/ffs_dss_wifi_provisionee_state.o libraries/nsd/ffs/ffs_dss_compute_configuration_data_request.o libraries/nsd/ffs/ffs_dss_operation_report.o libraries/nsd/ffs/ffs_data_model.o libraries/nsd/ffs/ffs_convert_wifi_provisionee_state.o libraries/nsd/ffs/ffs_convert_wifi_scan_result.o libraries/nsd/ffs/ffs_wifi_connection_attempt_list.o libraries/nsd/ffs/ffs_wifi_provisionee_state.o libraries/nsd/ffs/ffs_wifi_provisionee_user_network.o libraries/nsd/ffs/ffs_wifi_configuration_list.o libraries/nsd/ffs/ffs_convert_wifi_connection_attempt.o libraries/nsd/ffs/ffs_result.o libraries/nsd/ffs/ffs_convert_wifi_connection_details.o libraries/nsd/ffs/ffs_dss_registration_state.o libraries/nsd/ffs/ffs_dss_start_provisioning_session_response.o libraries/nsd/ffs/ffs_dss_post_wifi_scan_data_request.o libraries/nsd/ffs/ffs_dss_get_wifi_credentials_response.o libraries/nsd/ffs/ffs_circular_buffer.o libraries/nsd/ffs/ffs_convert_wifi_security_protocol.o libraries/nsd/ffs/ffs_linux_configuration_map.o libraries/nsd/ffs/ffs_dss_operation_get_wifi_credentials.o libraries/nsd/ffs/ffs_raspbian_wireless_tools.o libraries/nsd/ffs/ffs_cloud_bind.o libraries/nsd/ffs/ffs_linux_error_details.o libraries/nsd/ffs/ffs_convert_wifi_connection_state.o libraries/nsd/ffs/ffs_dss_report_result.o libraries/nsd/ffs/ffs_logging.o libraries/nsd/ffs/ffs_cloud_token.o libraries/nsd/ffs/ffs_json.o libraries/nsd/ffs/ffs_raspbian_wifi_manager.o libraries/nsd/ffs/ffs_dss_registration_details.o libraries/nsd/ffs/ffs_stream.o libraries/nsd/ffs/ffs_linux_user_context.o libraries/nsd/ffs/ffs_hex.o libraries/nsd/ffs/ffs_configuration_map.o libraries/nsd/miniupnpc/upnpc_cmd.o libraries/nsd/miniupnpc/upnpc_web.o libraries/nsd/miniupnpc/upnpc_data_model.o libraries/nsd/miniupnpc/port_mapping.o libraries/nsd/dhcpc/dhcpc.o libraries/nsd/dhcp_common/packet.o libraries/nsd/dhcp_common/options.o libraries/nsd/upgrade/rsaVerify.o libraries/nsd/upgrade/sd_backup.o libraries/nsd/upgrade/sd.o libraries/nsd/upgrade/lock_text.o libraries/nsd/upgrade/bigNumber.o libraries/nsd/upgrade/local.o libraries/nsd/upgrade/common.o libraries/nsd/upgrade/main.o libraries/nsd/tdpc/tdp_cmd.o libraries/nsd/tdpc/tdp_client.o libraries/nsd/remote_debugger/remote_debugger.o libraries/nsd/remote_debugger/sd_log.o libraries/nsd/telemetry/telemetry.o libraries/nsd/telemetry/telemetry_data_model.o libraries/nsd/telemetry/telemetry_sysinfo.o libraries/nsd/telemetry/telemetry_collect.o libraries/nsd/telemetry/telemetry_post.o libraries/nsd/tmpd/tmpd_utils.o libraries/nsd/tmpd/tmpd.o libraries/nsd/tmpd/script_business.o libraries/wlan/wlan_module/onboarding.o libraries/wlan/wlan_module/wlan.o libraries/wlan/wlan_module/wifi_control.o libraries/wlan/wlan_module/wlan_data_model.o libraries/wlan/wlan_module/wlan_monitor.o libraries/wlan/wlan_module/wlan_sta.o libraries/wlan/wlan_module/wlan_backup.o libraries/wlan/wlan_module/wlan_ap.o libraries/wlan/wlan_module/wlan_mode_switch.o libraries/wlan/wlan_module/utils.o libraries/wlan/wlan_module/soft_ap.o libraries/wlan/wlan_module/wlan_cascade.o libraries/wlan/wlan_module/cmd.o libraries/wlan/wlan_module/wlan_common.o libraries/wlan/wlan_module/wlan_manager.o libraries/wlan/libwlan_adapter/wlan_region.o libraries/wlan/libwlan_adapter/wlan_adapter.o libraries/wlan/libwlan_adapter/wlan_hostapd.o libraries/wlan/libwlan_adapter/wlan_utils.o libraries/wlan/libwlan_adapter/wlan_adapter_rtl.o libraries/wlan/libwlan_adapter/wlan_script.o libraries/wlan/libwlan_adapter/wlan_wpa_supplicant.o libraries/wlan/libwlan_adapter/wlan_adapter_wq.o libraries/debug_tools/debug_tools/debug_tools_data_model.o libraries/debug_tools/debug_tools/debug_tools.o libraries/debug_tools/debug_tools/coredump.o libraries/libs/libesp32/esp32_insmod.o libraries/libs/libncnn/flatten.cpp.o libraries/libs/libncnn/blob.cpp.o libraries/libs/libncnn/simplestl.cpp.o libraries/libs/libncnn/convolution_mips.cpp.o libraries/libs/libncnn/cumulativesum.cpp.o libraries/libs/libncnn/pipelinecache.cpp.o libraries/libs/libncnn/mat_pixel_affine.cpp.o libraries/libs/libncnn/mat_pixel.cpp.o libraries/libs/libncnn/pipeline.cpp.o libraries/libs/libncnn/paramdict.cpp.o libraries/libs/libncnn/copyto.cpp.o libraries/libs/libncnn/net.cpp.o libraries/libs/libncnn/mat_pixel_drawing.cpp.o libraries/libs/libncnn/mat_pixel_rotate.cpp.o libraries/libs/libncnn/innerproduct_mips.cpp.o libraries/libs/libncnn/mat.cpp.o libraries/libs/libncnn/layer.cpp.o libraries/libs/libncnn/benchmark.cpp.o libraries/libs/libncnn/modelbin.cpp.o libraries/libs/libncnn/flatten_mips.cpp.o libraries/libs/libncnn/pooling_mips.cpp.o libraries/libs/libncnn/allocator.cpp.o libraries/libs/libncnn/datareader.cpp.o libraries/libs/libncnn/innerproduct.cpp.o libraries/libs/libncnn/relu_mips.cpp.o libraries/libs/libncnn/pooling.cpp.o libraries/libs/libncnn/simpleomp.cpp.o libraries/libs/libncnn/convolution.cpp.o libraries/libs/libncnn/input.cpp.o libraries/libs/libncnn/simpleocv.cpp.o libraries/libs/libncnn/mat_pixel_resize.cpp.o libraries/libs/libncnn/command.cpp.o libraries/libs/libncnn/cpu.cpp.o libraries/libs/libncnn/option.cpp.o libraries/libs/libncnn/gpu.cpp.o libraries/libs/libncnn/padding.cpp.o libraries/libs/libncnn/padding_mips.cpp.o libraries/libs/libncnn/relu.cpp.o libraries/libs/libncnn/c_api.cpp.o libraries/libs/libmediautil/tpmd5.o libraries/libs/libmediautil/h265parse.o libraries/libs/libmediautil/avbasicop.o libraries/libs/libmediautil/mbasicop.o libraries/libs/libmediautil/bitstream.o libraries/libs/libmediautil/h264parse.o libraries/libs/libmediautil/basicutil.o libraries/libs/libmediautil/mbuffer.o libraries/libs/libdetectcaps/detect_capability.o libraries/libs/libavdc/libavdc.o libraries/libs/libavdc/aec.o libraries/libs/libavdc/mpp_adapter.o libraries/libs/libavdc/audio.o libraries/libs/libavdc/rmem_calc.o libraries/libs/libavdc/video.o libraries/libs/libavdc/video_api.o libraries/libs/libavdc/aeawb.o libraries/libs/libaudio/samplerate.o libraries/libs/libaudio/audio_utils.o libraries/libs/libcamera/libimage.o libraries/libs/libcamera/libosd.o libraries/libs/libcamera/camera_sar_adc.o libraries/libs/libcamera/camera_cover.o libraries/libs/libcamera/libcover.o libraries/libs/libcamera/libadc.o libraries/libs/libcamera/camera_gpio.o libraries/libs/libcamera/libcamera.o libraries/libs/libcamera/camera_osd.o libraries/libs/libcamera/camera_image.o libraries/libs/libcamera/tpcam_osd.o libraries/libs/libopenapi/fast_openapi_api.o libraries/libs/libopenapi/lib_openapi.o libraries/libs/libmotor/spi_motor_worker.o libraries/libs/libmotor/spi_motor.o libraries/libs/libds/ds_module_ctrl.o libraries/libs/libds/ds_trans_rule.o libraries/libs/libds/ds_blob_data.o libraries/libs/libds/ds_module.o libraries/libs/libds/ds_trans_ctrl.o libraries/libs/libds/ds_slp_parser.o libraries/libs/libds/ds_convert.o libraries/libs/libds/ds_model.o libraries/libs/libds/ds_flash.o libraries/libs/libds/ds_diag.o libraries/libs/libspeaker/libspeaker.o libraries/libs/libspeaker/speaker.o libraries/libs/libsmartdata/smart_data_format.o libraries/libs/libsdm/smart_data.o libraries/libs/libsdm/property.o libraries/libs/libsdm/system.o libraries/libs/libsdm/audio.o libraries/libs/libsdm/permission.o libraries/libs/libjpeg_stream/libjpeg_stream.o libraries/libs/libpwr/pwr.o libraries/libs/libflashio/flashio.o libraries/libs/libtpssl/commonssl.o libraries/libs/libtpssl/tcpApi.o libraries/libs/libtpssl/sslApi.o libraries/libs/libz/deflate.o libraries/libs/libz/adler32.o libraries/libs/libz/gzclose.o libraries/libs/libz/gzread.o libraries/libs/libz/gzwrite.o libraries/libs/libz/zutil.o libraries/libs/libz/inftrees.o libraries/libs/libz/crc32.o libraries/libs/libz/inflate.o libraries/libs/libz/inffast.o libraries/libs/libz/uncompr.o libraries/libs/libz/compress.o libraries/libs/libz/trees.o libraries/libs/libz/infback.o libraries/libs/libz/gzlib.o -Lstaging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/lib -Lstaging_dir/target-mips-openwrt-linux-uclibc-c200v5/lib -L../sdk/soc/T23/toolchain/mips-gcc540-glibc222-64bit-r3.3.0.smaller/mips-linux-gnu/libc/uclibc/usr/lib -L../sdk/soc/T23/toolchain/mips-gcc540-glibc222-64bit-r3.3.0.smaller/mips-linux-gnu/libc/uclibc/lib -Lstaging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/lib/libiconv-full/lib -Lstaging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/lib/libintl-full/lib -Wl,--gc-sections -lidleworker -ldms_tool -ldms -lutils -lmbedtls -lmbedx509 -lmbedcrypto -ljson -lpthread -lm -ludt -ltptimer -ldl -lrt -lwpactrl -Lstaging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/lib/mpp/ -limp -lsysutils -lalog -laudioProcess -Wl,-rpath-link=staging_dir/target-mips-openwrt-linux-uclibc-c200v5/usr/lib" libraries/avts/p2p/stun.o: In function `stunParseHostName': /home/linzihao/Code/onvif1/NVMP/nvmp/build_dir/target-mips-openwrt-linux-uclibc-c200v5/avts/streams/p2p/stun.c:1198: warning: gethostbyname is obsolescent, use getnameinfo() instead. libraries/nsd/onvif/onvif_srv.o: In function `check_digest_auth': /home/linzihao/Code/onvif1/NVMP/nvmp/build_dir/target-mips-openwrt-linux-uclibc-c200v5/nsd/modules/onvif/onvif_server/onvif_srv.c:549: undefined reference to `get_timestamp1' /home/linzihao/Code/onvif1/NVMP/nvmp/build_dir/target-mips-openwrt-linux-uclibc-c200v5/nsd/modules/onvif/onvif_server/onvif_srv.c:576: undefined reference to `get_timestamp1' libraries/nsd/onvif/onvif_srv.o: In function `onvif_proc_data_srv': /home/linzihao/Code/onvif1/NVMP/nvmp/build_dir/target-mips-openwrt-linux-uclibc-c200v5/nsd/modules/onvif/onvif_server/onvif_srv.c:604: undefined reference to `get_timestamp1' /home/linzihao/Code/onvif1/NVMP/nvmp/build_dir/target-mips-openwrt-linux-uclibc-c200v5/nsd/modules/onvif/onvif_server/onvif_srv.c:612: undefined reference to `get_timestamp1' collect2: error: ld returned 1 exit status _这个报错什么意思

filetype

我想我們先整合一下,先給我擴充後的整個完整目錄結構:my-app/ ├── README.md ├── Makefile ├── .gitignore ├── .editorconfig ├── .prettierrc ├── .eslintrc.cjs ├── .golangci.yml ├── .dockerignore ├── .vscode/ │ ├── extensions.json │ └── settings.json │ ├── contracts/ # 契約單一真相(SSOT) │ ├── common.yaml # 全域元資料(servers、security、RBAC、components 共用) │ ├── domains/ │ │ ├── users.yaml # 使用者領域 schema/paths 片段 │ │ └── auth.yaml # 認證授權相關 schema/paths 片段 │ ├── endpoints/ │ │ ├── users.list.yaml # 端點片段(可拆分便於維護) │ │ └── users.detail.yaml │ └── openapi.base.yaml # OpenAPI 合成基底(版本/聯絡/License 等) │ ├── api/ # 由 contracts 合成的 OpenAPI(生成物) │ ├── openapi.yaml # 最終合成 OpenAPI │ └── snapshot/ │ └── openapi.2025-10-27.yaml # 每次 CI 產生快照(便於 diff 與回滾) │ ├── scripts/ # 生成/驗證/工具腳本 │ ├── contracts-to-openapi.mjs # 合併 contracts → api/openapi.yaml │ ├── gen-openapi.sh # 調用 oapi-codegen / openapi-typescript / zod wrap │ ├── gen-zod-from-openapi.mjs # 將 TS types 轉 zod schema(或直接嵌入) │ ├── validate-openapi.mjs # 基於 spectral 或 openapi-diff 驗證 │ ├── validate-artifact.mjs # 驗證 repo/data 與 schema(CI 用) │ ├── bump-version.mjs # 語義化版本管理 │ └── release-notes.mjs # 變更日誌生成 │ ├── repo/ # Artifact 倉庫(可被 Gateway/mock/e2e 使用) │ ├── api/ │ │ ├── index.json # 路由索引(method/path → flow 與 data 映射) │ │ └── flows/ │ │ ├── users.list.flow.yaml │ │ └── users.detail.flow.yaml │ ├── data/ # 假資料(E2E 與 Mock 使用) │ │ ├── users.list.v1.json │ │ ├── users.detail.u_1.v1.json │ │ └── seed/ │ │ └── users.seed.json │ ├── plugins/ # JS 外掛(goja) │ │ ├── search.js │ │ └── helpers.js │ └── validators/ # 前後端共用 schema 定義(可選) │ ├── zod.ts │ └── ajv.ts │ ├── gateway/ # Artifact Gateway(Golang) │ ├── cmd/ │ │ └── artifact-gateway/ │ │ └── main.go # 啟動 HTTP、讀取 REPO_BASE、註冊路由 /mock /repo │ ├── internal/ │ │ ├── gateway/ │ │ │ ├── server.go # 路由、middleware(RBAC、logging、recover) │ │ │ └── match.go # 依 repo/api/index.json 匹配端點 │ │ └── flows/ │ │ ├── engine.go # Context、Step、OperatorRegistry、RespondStep │ │ ├── dataset.go # DataSource 介面、MemoryDataSource │ │ ├── ops.go # 運算子:filterAndPaginate、findById、checkEmailUnique、assignId、js 代理 │ │ ├── plugins.go # goja VM、外掛搜尋路徑、函式執行 │ │ ├── validator.go # request/response schema 驗證(可接 gojsonschema) │ │ ├── rbac.go # x-role / JWT claims 驗證(開發期) │ │ └── ops_test.go # 單元測試(涵蓋四個運算子與 JS 外掛) │ ├── testdata/ │ │ ├── repo/ # 測試專用 repo 拷貝 │ │ │ ├── api/index.json │ │ │ ├── data/users.list.v1.json │ │ │ └── plugins/search.js │ │ └── requests/ │ │ └── users.create.json │ ├── Dockerfile │ └── go.mod │ ├── backend/ # 真實後端服務(Golang) │ ├── cmd/ │ │ └── api/ │ │ └── main.go # 真實 API 入口(生產使用) │ ├── pkg/ │ │ ├── gen/ # oapi-codegen 生成 │ │ │ └── openapi.gen.go │ │ ├── handlers/ │ │ │ ├── users.go │ │ │ └── health.go │ │ ├── middlewares/ │ │ │ ├── logger.go │ │ │ └── auth.go │ │ ├── models/ │ │ │ └── user.go │ │ ├── storage/ │ │ │ └── memory.go │ │ └── server/ │ │ └── router.go │ ├── api/ │ │ └── openapi.yaml # 從 /api 同步或軟鏈接,供 oapi-codegen │ ├── Dockerfile │ ├── go.mod │ └── go.sum │ ├── frontend/ # Angular 前端 │ ├── src/ │ │ ├── app/ │ │ │ ├── core/ │ │ │ │ ├── api/ │ │ │ │ │ ├── types.gen.ts # openapi-typescript 生成 │ │ │ │ │ └── zod.gen.ts # zod schema(由腳本生成或手寫) │ │ │ │ ├── artifact/ │ │ │ │ │ ├── artifact.service.ts # 以 /mock 或 /repo 讀取資料 │ │ │ │ │ └── artifact.spec.ts # 與 repo/data 一致性測試 │ │ │ │ ├── datasource/ │ │ │ │ │ ├── datasource.service.ts # 資料來源狀態管理(Mock/Repo/API) │ │ │ │ │ ├── datasource.interceptor.ts# 附加 header 與監測請求 │ │ │ │ │ └── datasource.model.ts │ │ │ │ ├── config/config.service.ts │ │ │ │ └── utils/http-error.util.ts │ │ │ ├── features/ │ │ │ │ └── users/ │ │ │ │ ├── users-list/ │ │ │ │ │ ├── users-list.component.ts │ │ │ │ │ └── users-list.component.html │ │ │ │ └── users-detail/ │ │ │ │ ├── users-detail.component.ts │ │ │ │ └── users-detail.component.html │ │ │ ├── shared/ │ │ │ │ ├── components/ │ │ │ │ └── pipes/ │ │ │ └── devtools/ │ │ │ ├── datasource-switcher/ │ │ │ │ ├── datasource-switcher.component.ts │ │ │ │ ├── datasource-switcher.component.html │ │ │ │ └── datasource-switcher.component.scss │ │ │ └── request-log-panel/ │ │ │ ├── request-log-panel.component.ts │ │ │ └── request-log-panel.component.html │ │ ├── environments/ │ │ │ ├── environment.ts # dev:預設 /mock │ │ │ └── environment.prod.ts # prod:預設 /api │ │ ├── main.ts │ │ └── styles.scss │ ├── cypress/ # e2e 測試 │ │ ├── e2e/ │ │ │ ├── datasource-switch.cy.ts │ │ │ └── users-flow.cy.ts │ │ └── support/ │ │ └── e2e.ts │ ├── Dockerfile │ ├── angular.json │ ├── package.json │ └── tsconfig.json │ ├── config/ │ ├── cloudbuild.yaml # GCP Cloud Build(或 GitHub Actions 對等) │ └── k8s/ │ ├── namespace.yaml │ ├── gateway.deployment.yaml │ ├── gateway.service.yaml │ ├── backend.deployment.yaml │ ├── backend.service.yaml │ └── ingress.yaml │ ├── artifacts/ │ ├── template.yaml # Artifact 模板與鏡像標籤參數 │ ├── docker-compose.dev.yaml # 本地整包開發(含 repo 暴露與 /mock 代理) │ └── helm/ │ └── my-app/ │ ├── Chart.yaml │ ├── values.yaml │ └── templates/ │ ├── deployment.yaml │ ├── service.yaml │ └── ingress.yaml │ └── .github/ └── workflows/ └── ci.yml # GitHub Actions(或與 Cloud Build 並存)

filetype

角色:系统测试工程师 背景:擅长系统测试设计,擅长系统测试、自动化测试,安全测试等,是个综合的高级测试工程师 任务:根据用户输入的需求描述,完成测试设计 需求描述:greenplum分布式数据库,一个集群,安装在两个服务器上,针对gprecoverseg工具,编写测试用例,要求覆盖所有场景。 任务要求:编写详细可执行的测试用例 参考材料:gprecoverseg的参数: COMMAND NAME: gprecoverseg Recovers a primary or mirror segment instance that has been marked as down (if mirroring is enabled). ****************************************************** Synopsis ****************************************************** gprecoverseg [-p <new_recover_host>[,...]] |-i <recover_config_file> [-d <master_data_directory>] [-B <batch_size>] [-b <segment_batch_size>] [--differential] [-F] [-a] [-q] [-s] [--no-progress] [-l <logfile_directory>] gprecoverseg -r gprecoverseg -o <output_recover_config_file> [-p <new_recover_host>[,...]] gprecoverseg -? gprecoverseg --version ****************************************************** DESCRIPTION ****************************************************** In a system with mirrors enabled, the gprecoverseg utility reactivates a failed segment instance and identifies the changed database files that require resynchronization. Once gprecoverseg completes this process, the system goes into resyncronizing mode until the recovered segment is brought up to date. The system is online and fully operational during resyncronization. A segment instance can fail for several reasons, such as a host failure, network failure, or disk failure. When a segment instance fails, its status is marked as down in the Greenplum Database system catalog, and its mirror is activated in change tracking mode. In order to bring the failed segment instance back into operation again, you must first correct the problem that made it fail in the first place, and then recover the segment instance in Greenplum Database using gprecoverseg. Segment recovery using gprecoverseg requires that you have an active mirror to recover from. For systems that do not have mirroring enabled, or in the ev

filetype

static int validatePartitions(TP_HEADER* header) { int ret = 0; uint32_t service_offset = ntohl(header->servicefsOffset); uint32_t service_length = ntohl(header->servicefsRealFsLen); uint32_t model_offset = ntohl(header->modelFsOffset); uint32_t model_length = ntohl(header->modelFsLen); uint32_t kernel_romfs_offset = ntohl(header->kernelOffset); uint32_t kernel_romfs_length = model_offset - ntohl(header->kernelOffset); uint32_t flash_read_begin = CFG_FLASH_SIZE; uint32_t flash_read_end = 0; int b_check_recover = 0; //array of validation crc's. unsigned char* crc[] = {header->kernelAndRootfsCRC, header->serviceCRC}; //array of partition offsets & lengths. uint32_t offset[] = {kernel_romfs_offset, model_offset}; uint32_t length[] = {kernel_romfs_length, model_length + service_length}; //array of messages. char* dbg_msg[] = {"kernel and rootfs", "rootfs data"}; //array of partition type flags to decide which partition to be validated. uint32_t partition_flags[] = {CONTENT_TYPE_KERNEL_ROOTFS, CONTENT_TYPE_SERVICE}; unsigned char md5Tmp[MD5SUM_LEN] = {0}; unsigned char md5Backup[MD5SUM_LEN] = {0}; unsigned char* base = NULL; int i; VF_DBG("Validating partitions..."); VF_DBG("UBoot Offset: %x, Length: %x", ntohl(header->bootloaderOffset), ntohl(header->bootloaderLen)); if(ntohl(header->bootloaderOffset) != BOOTLOADER_OFFSET || ntohl(header->bootloaderLen) != BOOTLOADER_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("Kernel Offset: %x, Length: %x", ntohl(header->kernelOffset), ntohl(header->kernelLen)); if (ntohl(header->kernelOffset) != KERNEL_ROMFS_OFFSET) { return ERR_INVALID_TP_HEADER; } VF_DBG("User Config Offset: %x, Length: %x", ntohl(header->ucOffset), ntohl(header->ucLen)); if(ntohl(header->ucOffset) != UC_OFFSET || ntohl(header->ucLen) != UC_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("FactoryInfo Offset: %x, Length: %x", ntohl(header->factoryInfoOffset), ntohl(header->factoryInfoLen)); if(ntohl(header->factoryInfoOffset) != FACTORY_INFO_OFFSET || ntohl(header->factoryInfoLen) != FACTORY_INFO_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("TpHeader Offset: %x, Length: %x", ntohl(header->tpHeaderOffset), ntohl(header->tpHeaderLen)); if(ntohl(header->tpHeaderOffset) != TP_HEADER_OFFSET || ntohl(header->tpHeaderLen) != TP_HEADER_LEN) { return ERR_INVALID_TP_HEADER; } //verifying partition CRC. for (i = 0; i < sizeof(crc) / sizeof(char *); i++) { if (flash_read_begin > offset[i]) { flash_read_begin = offset[i]; } if (flash_read_end < offset[i] + length[i]) { flash_read_end = offset[i] + length[i]; } } base = (char *)CONFIG_LOADADDR - flash_read_begin; if (flash_read_end < service_offset + kernel_romfs_length) { flash_read_end = service_offset + kernel_romfs_length; } ret = readFlash(flash_read_begin, base + flash_read_begin, flash_read_end - flash_read_begin); if (ret < 0) { printf("reading flash to RAM failed."); return ret; } for (i = 0; i < sizeof(crc) / sizeof(char *); i++) { VF_DBG("verifying %s partition [0x%x,0x%x]...", dbg_msg[i], offset[i], length[i]); memset(md5Tmp, 0, MD5SUM_LEN); VF_DBG("base: %p, offset: %p, length: %x\n", base, offset[i], (int)length[i]); calcMd5((char *)(base + offset[i]), (int)length[i], (char *)md5Tmp); //debug_print_md5(md5Tmp); //debug_print_md5(crc[i]); if (memcmp(md5Tmp, crc[i], MD5SUM_LEN) == 0) { VF_DBG("ok"); } else { VF_DBG("failed"); ret = ERR_PARTITION_VALIDATION_FAILED; if (partition_flags[i] == CONTENT_TYPE_SERVICE) { calcMd5((char *)(base + service_offset), kernel_romfs_length, md5Backup); } if (i == 0) { b_check_recover = 1; } } } if (b_check_recover) { //debug_print_md5(md5Backup); //debug_print_md5(header->kernelAndRootfsCRC); if (memcmp(md5Backup, header->kernelAndRootfsCRC, MD5SUM_LEN) == 0) { int erase_offset = 0; int write_offset = 0; for (erase_offset = 0; erase_offset < kernel_romfs_length; erase_offset++) { if (*(base + kernel_romfs_offset + erase_offset) != 0xFF) { break; } } printf("restore kernelAndRomfs, erase_offset=0x%x\n", erase_offset); if (erase_offset != kernel_romfs_length) { erase_offset = erase_offset / CFG_FLASH_SECTOR_SIZE * CFG_FLASH_SECTOR_SIZE; while (erase_offset < kernel_romfs_length) { feedWatchdog(); if (kernel_romfs_length - erase_offset <= ERASE_BLOCK_SIZE) { eraseWriteFlash(kernel_romfs_offset + erase_offset, NULL, kernel_romfs_length - erase_offset); erase_offset = kernel_romfs_length; } else { eraseWriteFlash(kernel_romfs_offset + erase_offset, NULL, ERASE_BLOCK_SIZE); erase_offset += ERASE_BLOCK_SIZE; } } } while (write_offset < kernel_romfs_length) { feedWatchdog(); if (kernel_romfs_length - write_offset <= WRITE_BLOCK_SIZE) { eraseWriteFlash(kernel_romfs_offset, base + service_offset, kernel_romfs_length); write_offset = kernel_romfs_length; } else { eraseWriteFlash(kernel_romfs_offset, base + service_offset, WRITE_BLOCK_SIZE); write_offset += WRITE_BLOCK_SIZE; } } } } return ret; }详细解析一下

filetype

#!/bin/bash echo "--------------------------------------------------------" printf "set variable ...\n" package_ip=172.22.126.50 get_path=/home/mdbs/MDBS/MDBS_V5.0.5/x86_64/zip #get_path=/home/mdbs/MDBS/MDBS_V5.0.4P04/x86_64/zip password="wvu7G55U2025" install_path=/home/MDBS_V5.0.6 #install_path=/home/MDBS_V5.0.4p04 deploy_log=/root/deploy.log ntp_ip=172.17.251.101 get_req_node_ip=192.168.6.71 node_password="mdbs-123" mount_path=/home/autest PYTHONPATH=$mount_path/hci/hci_python log_path=/root/mdbs_test.log printf "package_ip: %s\n" $package_ip printf "get_path: %s\n" $get_path printf "install_path: %s\n" $install_path printf "deploy_log: %s\n" $deploy_log printf "ntp_ip:%s\n" $ntp_ip printf "get_req_node_ip:%s\n" $get_req_node_ip printf "node_password:%s\n" $node_password printf "PYTHONPATH:%s\n" $PYTHONPATH printf "log_path:%s\n" $log_path sleep 10 printf "\n" echo "--------------------------------------------------------" printf "get package ...\n" ssh root@$get_req_node_ip "rm $install_path/MDBS_V* -rf" ssh root@$get_req_node_ip "sshpass -p $password scp root@$package_ip:$get_path/MD5.txt $install_path/" ssh root@$get_req_node_ip "sshpass -p $password scp root@$package_ip:$get_path/MDBS_V* $install_path/" rpm_md5=$(ssh root@$get_req_node_ip "cd $install_path; md5sum MDBS*") ssh root@$get_req_node_ip "cat $install_path/MD5.txt | grep '$rpm_md5'" if [ $? -ne 0 ]; then printf "rpm MD5 not same with MD5 txt!\n" exit 1 fi printf "\n" echo "--------------------------------------------------------" printf "deploy mdbs ...\n" ssh root@$get_req_node_ip "cd $install_path;sh install_mdbs.sh" > $deploy_log 2>&1 cat $deploy_log | grep "PLAY RECAP" -A 4 | grep "localhost" -B 3 | grep "failed=1" if [ $? -eq 0 ]; then printf "deploy mdbs rpm failed!\n" exit 1 fi ssh root@$get_req_node_ip -t "cd $install_path;sh recover_isolate_rebuild_ttl.sh; sh set_mgt_port.sh" printf "\n" echo "--------------------------------------------------------" printf "reset env ...\n" ntpdate -s $ntp_ip rm -f $log_path rm -rf /opt/macrosan/mdbs/config/* mkdir -p /opt/macrosan/mdbs/config/openssl sshpass -p $node_password scp root@$get_req_node_ip:/opt/macrosan/mdbs/config/openssl/* /opt/macrosan/mdbs/config/openssl/ sh cp_test_code.sh printf "\n" echo "--------------------------------------------------------" printf "run test ...\n" source /opt/macrosan/mdbs/py_env/bin/activate export PYTHONPATH=$PYTHONPATH nosetests $mount_path/hci/hci_test/script/tools/test.py >> $log_path 2>&1 printf "\n" echo "--------------------------------------------------------" printf "get result ...\n" python /root/get_test_result.py $log_path cp $log_path $mount_path 上述是shell脚本yr_test1.sh的内容,执行命令sh yr_test1.sh &,为什么在执行到ssh root@$get_req_node_ip "cd $install_path;sh install_mdbs.sh" > $deploy_log 2>&1后,[root@localhost ~]# ps -axu | grep test root 849261 0.0 0.0 22776 3812 pts/1 T 17:31 0:00 sh yr_test1.sh

filetype

#include <common.h> #include <command.h> #include "md5.h" #define ERR_NONE 0 #define ERR_GENERIC -1 #define ERR_RSA_CHECK_FAIL -2 #define ERR_HWID_NOT_FOUND -3 #define ERR_FWID_NOT_FOUND -4 #define ERR_HWID_NOT_SUPPORTED -5 #define ERR_FWID_NOT_SUPPORTED -6 #define ERR_PARTITION_TYPE_NOT_SUPPORTED -7 #define ERR_INCORRECT_FILE_SIZE -8 #define ERR_READ_FLASH -9 #define ERR_WRITE_FLASH -10 #define ERR_ERASE_FLASH -11 #define ERR_BAD_ADDRESS -12 #define ERR_MEMORY_ALLOC -13 #define ERR_INVALID_TP_HEADER -14 #define ERR_PARTITION_VALIDATION_FAILED -15 #define CFG_FLASH_BASE (0x0) #define DEFAULT_8MB_FLASH_SIZE (8*1024*1024) #ifndef FLASH_SIZE_IN_MB #define CFG_FLASH_SIZE (DEFAULT_8MB_FLASH_SIZE) #else #define CFG_FLASH_SIZE (FLASH_SIZE_IN_MB*1024*1024) #endif #define CFG_FLASH_SECTOR_SIZE (64*1024) #ifdef CONFIG_LOADADDR #undef CONFIG_LOADADDR #endif #define CONFIG_LOADADDR 0x22100000 /* Flash layout constants. */ #ifndef FACTORY_BOOT_OFFSET #define FACTORY_BOOT_OFFSET 0x0 #endif #ifndef FACTORY_BOOT_LEN #define FACTORY_BOOT_LEN 0x0001F000 #endif #ifndef FACTORY_INFO_OFFSET #define FACTORY_INFO_OFFSET (FACTORY_BOOT_OFFSET + FACTORY_BOOT_LEN) #endif #ifndef FACTORY_INFO_LEN #define FACTORY_INFO_LEN 0x00001000 #endif #ifndef RADIO_OFFSET #define RADIO_OFFSET (FACTORY_INFO_OFFSET + FACTORY_INFO_LEN) #endif #ifndef RADIO_LEN #define RADIO_LEN 0x10000 #endif #ifndef UC_OFFSET #define UC_OFFSET (RADIO_OFFSET + RADIO_LEN) #endif #ifndef UC_LEN #define UC_LEN 0x10000 #endif #ifndef BOOTLOADER_OFFSET #define BOOTLOADER_OFFSET (UC_OFFSET + UC_LEN) #endif #ifndef BOOTLOADER_LEN #define BOOTLOADER_LEN 0x10000 #endif #ifndef TP_HEADER_OFFSET #define TP_HEADER_OFFSET (BOOTLOADER_OFFSET + BOOTLOADER_LEN) #endif #ifndef TP_HEADER_LEN #define TP_HEADER_LEN 0x200 #endif #ifndef KERNEL_ROMFS_OFFSET #define KERNEL_ROMFS_OFFSET (TP_HEADER_OFFSET + TP_HEADER_LEN) #endif #ifdef USE_NAND_FLASH #define VERIFY_LEN 0x20000 #else #define VERIFY_LEN 0x10000 #endif #ifndef JFFS2_OFFSET #define ROOTFS_DATA_OFFSET ((CFG_FLASH_SIZE + TP_HEADER_OFFSET - VERIFY_LEN) / 2) #define ROOTFS_DATA_SIZE ((CFG_FLASH_SIZE - TP_HEADER_OFFSET - VERIFY_LEN) / 2) #endif #define MD5SUM_LEN 16 #define FW_ID_LEN 16 /* content type flags. */ #define CONTENT_TYPE_BOOTLOADER 0x0001 #define CONTENT_TYPE_KERNEL 0x0002 #define CONTENT_TYPE_ROMFS 0x0004 #define CONTENT_TYPE_JFFS2FS 0x0008 /* partition type flags. */ #define PARTITION_TYPE_BOOTLOADER CONTENT_TYPE_BOOTLOADER #define PARTITION_TYPE_KERNEL CONTENT_TYPE_KERNEL #define PARTITION_TYPE_ROOTFS_DATA CONTENT_TYPE_JFFS2FS /* define tp header */ #define MAGIC_LEN 20 #define CRC_LEN 16 #define FW_DESC_LEN 12 #if 1 #define VF_DBG(fmt, args...) \ printf("VF: %s: " fmt "\n" , __FUNCTION__ , ## args) #else #define VF_DBG(fmt, args...) do {} while (0) #endif #define ERR(fmt, ...) { \ printf("error: " fmt "\n", \ ## __VA_ARGS__ ); \ } typedef struct _TP_HEADER { unsigned int headerVersion; unsigned char magicNumber[MAGIC_LEN]; unsigned int kernelLoadAddress; unsigned int kernelEntryPoint; unsigned short vendorId; unsigned short zoneCode; unsigned int partitionNum; unsigned int factoryBootOffset; unsigned int factoryBootLen; unsigned int factoryInfoOffset; unsigned int factoryInfoLen; unsigned int radioOffset; unsigned int radioLen; unsigned int ucOffset; unsigned int ucLen; unsigned int bootloaderOffset; unsigned int bootloaderLen; unsigned int tpHeaderOffset; unsigned int tpHeaderLen; unsigned int kernelOffset; unsigned int kernelLen; unsigned int romFsOffset; unsigned int romFsLen; unsigned int jffs2FsOffset; unsigned int jffs2FsLen; unsigned char factoryInfoCRC[CRC_LEN]; unsigned char radioCRC[CRC_LEN]; unsigned char ubootCRC[CRC_LEN]; unsigned char kernelAndRomfsCRC[CRC_LEN]; unsigned char fwId[FW_ID_LEN]; unsigned char fwDescription[FW_DESC_LEN]; unsigned int fwIdBLNum; unsigned char fwIdBL[0][FW_ID_LEN]; unsigned char serviceCRC[CRC_LEN]; unsigned int isVerified; unsigned int jffs2RealFsLen; } TP_HEADER; static unsigned char gTpHeaderMagicNumber[MAGIC_LEN] = {0x55, 0xAA, 0x9D, 0xD1, 0xA8, 0xC8, 0x83, 0x31, 0xC9, 0x69, 0xFB, 0xBF, 0xBC, 0xF0, 0xD4, 0x32, 0x70, 0xC7, 0xAA, 0x55}; static int addr_flash(void* addr) { if((unsigned long)addr < 0 || (unsigned long)addr >= CFG_FLASH_SIZE) { printf("%p: Not a valid flash address!", addr); return ERR_BAD_ADDRESS; } return 0; } static int readFlash(uint32_t addrOffset, uint8_t* buf, uint32_t buflen) { int ret = 0; char cmdbuf[70]; //TODO:need to detect address type. ret = addr_flash((void*)addrOffset); if(ret < 0) { return ret; } // ret = addr_mem(buf); // if(ret < 0) // { // return ret; // } #ifdef USE_NAND_FLASH sprintf(cmdbuf, "nand read.e 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen); #else sprintf(cmdbuf, "sf probe 0;sf read 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen); #endif if(run_command(cmdbuf, 0) < 0) { return ERR_READ_FLASH; } return 0; } static int writeFlash(uint32_t addrOffset, uint8_t* buf, uint32_t buflen) { int ret = 0; char cmdbuf[70]; //TODO:need to detect address type. ret = addr_flash((void*)addrOffset); if(ret < 0) { return ret; } // ret = addr_mem(buf); // if(ret < 0) // { // return ret; // } #ifdef USE_NAND_FLASH sprintf(cmdbuf, "nand write.e 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen); #else sprintf(cmdbuf, "sf probe 0;sf erase 0x%x 0x%x;sf write 0x%x 0x%x 0x%x", addrOffset, buflen, (uint32_t)buf, addrOffset, buflen); #endif if(run_command(cmdbuf, 0) < 0) { return ERR_READ_FLASH; } return 0; } /* * Function Name: eraseFlash * Author: CaiBin * Date: 2014-11-07 * Description: Erase flash content of a given flash address. * Parameter: * addrOffset: Flash address to erase. * eraselen: Erase length in bytes. * buflen: Length of the data buf in bytes. * return: * 0: Succeeded; * ERR_ERASE_FLASH: Erase command execution error. * ERR_BAD_ADDRESS: Invalid address values passed. */ static int eraseFlash(uint32_t addrOffset, uint32_t eraselen) { int ret; char cmdbuf[70]; ret = addr_flash((void*)addrOffset); if (ret < 0) { return ret; } //if addr offset or eraselen is not on sector boundary, return err. if (0 != (addrOffset % CFG_FLASH_SECTOR_SIZE)) { ERR("%s: addrOffset is 0x%08x\n, not on sector boundary!", __func__, addrOffset); return ERR_BAD_ADDRESS; } if (0 != (eraselen % CFG_FLASH_SECTOR_SIZE)) { ERR("%s: eraselen is 0x%08x\n, not on sector boundary!", __func__, eraselen); return ERR_BAD_ADDRESS; } //TODO:need to detect address type. #ifdef USE_NAND_FLASH sprintf(cmdbuf, "nand erase 0x%x 0x%x", addrOffset, eraselen); #else sprintf(cmdbuf, "sf probe 0;sf erase 0x%x 0x%x", addrOffset, eraselen); #endif if (run_command(cmdbuf, 0) < 0) { return ERR_ERASE_FLASH; } return 0; } static void debug_print_md5(unsigned char *digest) { int i = 0; for (i = 0; i < 16; i++) printf("%02x", digest[i]); printf("\n"); } static void calcMd5(char *data, int size, char *md5) //计算md5 { MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, data, size); MD5_Final(md5, &ctx); } #ifdef USE_NAND_FLASH /* 参考自 lib_uip/apps/upgrade/http_upgrade.c中的executeUpgrade_nand() */ static int restore_Mini_Main_nand(TP_HEADER *header, unsigned char *base) { int ret = 0; int i =0; printf("execute nand flash restore kernelRom...\n"); /* ntohl(tp_head->tphead_len) + ntohl(tp_head->kernel_len) + ntohl(tp_head->romfs_len) */ /* tp_header, kernel, romFS */ uint32_t offset[] = { TP_HEADER_OFFSET, KERNEL_OFFSET, ntohl(header->romFsOffset) }; uint32_t eraseLen[] = { KERNEL_OFFSET - TP_HEADER_OFFSET, ntohl(header->romFsOffset) - KERNEL_OFFSET, ntohl(header->jffs2FsOffset) - ntohl(header->romFsOffset) }; uint32_t writeLen[] = { TP_HEADER_LEN, ntohl(header->kernelLen), ntohl(header->romFsLen) }; uint8_t* baseArr[] ={ (uint8_t*)base, (uint8_t*)((uint8_t*)base + TP_HEADER_LEN), (uint8_t*)((uint8_t*)base + TP_HEADER_LEN + ntohl(header->kernelLen)) }; for (i = 0; i < sizeof(offset) / sizeof(uint32_t); i++) { ret = eraseFlash(offset[i], eraseLen[i]); if (ret < 0) { goto error_exit; } //start to write firmware. printf("[step%d] write offset: 0x%08x, from: %p, size: 0x%08x\n", i + 1, offset[i], baseArr[i], writeLen[i]); ret = writeFlash(offset[i], baseArr[i], writeLen[i]); if (ret < 0) { goto error_exit; } } return 0; error_exit: ERR("erase or write nand flash failed!"); return ret; } #endif /* * Function Name: validatePartitions * Author: CaiBin * Date: 2014-11-07 * Description: Check valid firmware partitions. * Validate partition offsets,lengths and CRC's in TP Header. * Parameter: * header: Points to the TP Header partition of the firmware image to validate. * return: * 0: Succeeded; * ERR_INVALID_TP_HEADER: Firmware has not all partitions. * ERR_PARTITION_VALIDATION_FAILED: Partition CRC verification failed. */ static int validatePartitions(TP_HEADER* header, uint32_t partition_type) //固件分区校验函数,用于验证固件中多个关键分区(内核、romfs、rootfs 等)的完整性。它通过比较各分区的 MD5 校验值来判断是否损坏,并在必要时尝试从备份区域恢复。 { int ret = 0; uint32_t kernel_romfs_length = ntohl(header->kernelLen) + ntohl(header->romFsLen); //array of validation crc's. unsigned char* crc[] = {header->kernelAndRomfsCRC, header->serviceCRC}; //array of partition offsets & lengths. #ifdef JFFS2_OFFSET #ifdef USE_NAND_FLASH uint32_t rootfs_data_offset = ntohl(header->jffs2FsOffset); #else uint32_t rootfs_data_offset = KERNEL_ROMFS_OFFSET + ntohl(header->kernelLen) + ntohl(header->romFsLen); #endif uint32_t offset[] = {KERNEL_ROMFS_OFFSET, rootfs_data_offset}; uint32_t length[] = {kernel_romfs_length, ntohl(header->jffs2RealFsLen)}; #else uint32_t offset[] = {KERNEL_ROMFS_OFFSET, ROOTFS_DATA_OFFSET}; uint32_t length[] = {kernel_romfs_length, ROOTFS_DATA_SIZE}; #endif //array of messages. char* dbg_msg[] = {"kernel and romfs", "rootfs data"}; //array of partition type flags to decide which partition to be validated. uint32_t partition_flags[] = {PARTITION_TYPE_KERNEL, PARTITION_TYPE_ROOTFS_DATA}; unsigned char md5Tmp[MD5SUM_LEN] = {0}; unsigned char md5RootfsData[MD5SUM_LEN] = {0}; unsigned char* base = NULL; int i; VF_DBG("Validating partitions..."); VF_DBG("Factory Boot Offset: %x, Length: %x", ntohl(header->factoryBootOffset), ntohl(header->factoryBootLen)); if(ntohl(header->factoryBootOffset) != FACTORY_BOOT_OFFSET || ntohl(header->factoryBootLen) != FACTORY_BOOT_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("Factory Info Offset: %x, Length: %x", ntohl(header->factoryInfoOffset), ntohl(header->factoryInfoLen)); if(ntohl(header->factoryInfoOffset) != FACTORY_INFO_OFFSET || ntohl(header->factoryInfoLen) != FACTORY_INFO_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("Radio Offset: %x, Length: %x", ntohl(header->radioOffset), ntohl(header->radioLen)); if(ntohl(header->radioOffset) != RADIO_OFFSET || ntohl(header->radioLen) != RADIO_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("User Config Offset: %x, Length: %x", ntohl(header->ucOffset), ntohl(header->ucLen)); if(ntohl(header->ucOffset) != UC_OFFSET || ntohl(header->ucLen) != UC_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("UBoot Offset: %x, Length: %x", ntohl(header->bootloaderOffset), ntohl(header->bootloaderLen)); if(ntohl(header->bootloaderOffset) != BOOTLOADER_OFFSET || ntohl(header->bootloaderLen) != BOOTLOADER_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("TP Header Offset: %x, Length: %x", ntohl(header->tpHeaderOffset), ntohl(header->tpHeaderLen)); if(ntohl(header->tpHeaderOffset) != TP_HEADER_OFFSET || ntohl(header->tpHeaderLen) != TP_HEADER_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("Kernel Offset: %x, Length: %x", ntohl(header->kernelOffset), ntohl(header->kernelLen)); #ifndef USE_NAND_FLASH if (ntohl(header->kernelOffset) != KERNEL_ROMFS_OFFSET) #else if (ntohl(header->kernelOffset) != KERNEL_OFFSET) #endif { return ERR_INVALID_TP_HEADER; } VF_DBG("Romfs Offset: %x, Length: %x", ntohl(header->romFsOffset), ntohl(header->romFsLen)); VF_DBG("JFFS2 Offset: %x, Length: %x", ntohl(header->jffs2FsOffset), ntohl(header->jffs2FsLen)); #ifndef USE_NAND_FLASH /* It is not true for nand, because there are gaps in kernel and romFS partitions */ if(ntohl(header->kernelLen) + ntohl(header->romFsLen) + ntohl(header->jffs2FsLen)+ VERIFY_LEN + KERNEL_ROMFS_OFFSET #ifdef MTD_USER_RECORD_PARTS + USER_RECORD_PARTITION_LEN #endif != CFG_FLASH_SIZE) { return ERR_INVALID_TP_HEADER; } #endif //verifying partition CRC. base = (char *)CONFIG_LOADADDR; for (i = 0; i < sizeof(crc) / sizeof(char *); i++) { if (partition_type & partition_flags[i]) { VF_DBG("verifying %s partition [0x%x,0x%x]...", dbg_msg[i], offset[i], length[i]); #ifdef USE_NAND_FLASH int nand_ret = 0; base = (unsigned char *)CONFIG_LOADADDR + ntohl(header->tpHeaderLen) * 2; if (KERNEL_ROMFS_OFFSET == offset[i]) /* get kernel + romfs to cal crc */ { nand_ret = readFlash(ntohl(header->kernelOffset), (uint8_t *)base, ntohl(header->kernelLen)); if (nand_ret < 0) { VF_DBG("CRC verifying reading flash to RAM failed.\n"); return nand_ret; } nand_ret = readFlash(ntohl(header->romFsOffset), (uint8_t *)(base + ntohl(header->kernelLen)), ntohl(header->romFsLen)); if (nand_ret < 0) { VF_DBG("CRC verifying reading flash to RAM failed.\n"); return nand_ret; } } else { nand_ret = readFlash(offset[i], (uint8_t *)base, length[i]); if (nand_ret < 0) { VF_DBG("CRC verifying reading flash to RAM failed.\n"); return nand_ret; } } memset(md5Tmp, 0, MD5SUM_LEN); printf("base: %p, offset: %p, length: %x\n", base, base, (int)length[i]); calcMd5((char *)(base), (int)length[i], (char *)md5Tmp); #else memset(md5Tmp, 0, MD5SUM_LEN); VF_DBG("base: %p, offset: %p, length: %x", base, base + offset[i], (int)length[i]); calcMd5((char *)(base + offset[i]), (int)length[i], (char *)md5Tmp); //读取 Flash 数据到内存,计算 MD5 #endif // debug_print_md5(md5Tmp); // debug_print_md5(crc[i]); if (memcmp(md5Tmp, crc[i], MD5SUM_LEN) == 0) //与 header 中的原始 MD5 对比; { VF_DBG("ok"); } else { VF_DBG("failed"); /* 固件kernel&RomFS损坏, 尝试从JFFS2恢复 */ if (ERR_PARTITION_VALIDATION_FAILED == ret && partition_flags[i] == PARTITION_TYPE_ROOTFS_DATA) //循环到第二个 { #ifdef USE_NAND_FLASH calcMd5((char *)(base + TP_HEADER_LEN), (int)kernel_romfs_length, (char *)md5RootfsData); #else #ifdef JFFS2_OFFSET calcMd5((char *)(base + rootfs_data_offset + TP_HEADER_LEN), kernel_romfs_length, md5RootfsData); #else calcMd5((char *)(base + ROOTFS_DATA_OFFSET + TP_HEADER_LEN), kernel_romfs_length, md5RootfsData); //从 JFFS2 中计算出 MD5 值,用于后续恢复操作。 #endif #endif } ret = ERR_PARTITION_VALIDATION_FAILED; } } } if (ERR_PARTITION_VALIDATION_FAILED == ret) { if (memcmp(md5RootfsData, header->kernelAndRomfsCRC, MD5SUM_LEN) == 0) { printf("restore kernelAndRomfs\n"); #ifdef USE_NAND_FLASH restore_Mini_Main_nand(header, base); #else #ifdef JFFS2_OFFSET writeFlash(TP_HEADER_OFFSET, base + rootfs_data_offset, ntohl(header->tpHeaderLen) + kernel_romfs_length); #else writeFlash(TP_HEADER_OFFSET, base + ROOTFS_DATA_OFFSET, ROOTFS_DATA_SIZE); #endif #endif } } return ret; } static int checkTpHeaderMagicNumber(TP_HEADER* header) { int i; if (memcmp(gTpHeaderMagicNumber, header->magicNumber, MAGIC_LEN) == 0) { return 0; } else { return 1; } } int validateFirmwareWithRecover(void) { int ret = 0; unsigned char skipValidate = 0; TP_HEADER* header = NULL; TP_HEADER* header_bak = NULL; uint32_t partitions = PARTITION_TYPE_KERNEL | PARTITION_TYPE_ROOTFS_DATA; //return ERR_PARTITION_VALIDATION_FAILED;// skip validate for test #ifdef USE_NAND_FLASH /* read tp_header to RAM */ ret = readFlash(TP_HEADER_OFFSET, (uint8_t*)CONFIG_LOADADDR, TP_HEADER_LEN); if (ret < 0) { ERR("reading nandflash tp_head to RAM failed."); return ret; } /* read tp_header_bak (verify) to RAM * don't take into account for not MINI_MAIN **/ ret = readFlash(CFG_FLASH_BASE + CFG_FLASH_SIZE - VERIFY_LEN, (uint8_t*)(CONFIG_LOADADDR + TP_HEADER_LEN), TP_HEADER_LEN); if (ret < 0) { ERR("reading nandflash tp_head_bak to RAM failed."); return ret; } header = (TP_HEADER*)(CONFIG_LOADADDR); header_bak = (TP_HEADER*)(CONFIG_LOADADDR + TP_HEADER_LEN); #else /* copy whole flash image to RAM. */ VF_DBG("copying flash to 0x%x", CONFIG_LOADADDR); ret = readFlash(0, CONFIG_LOADADDR, CFG_FLASH_SIZE); if (ret < 0) { printf("reading flash to RAM failed."); return ret; } VF_DBG("ret=%d(%p)", ret, &ret); header = (TP_HEADER*)(CONFIG_LOADADDR + TP_HEADER_OFFSET); header_bak = (TP_HEADER*)(CONFIG_LOADADDR + CFG_FLASH_SIZE - VERIFY_LEN); #endif if (checkTpHeaderMagicNumber(header_bak)) //如果备份 header 的 Magic Number 不合法,则设为 NULL; { header_bak = NULL; //如果备份 header 的 isVerified 字段为 1,表示已验证过,跳过校验。 } else if (header_bak->isVerified == 1){ skipValidate = 1; } if (checkTpHeaderMagicNumber(header)) //如果主 header 损坏,但备份 header 有效;则擦除主 header 所在区域,将备份写入 { if (header_bak) { printf("restore tpHeader\n"); #ifdef USE_NAND_FLASH eraseFlash(TP_HEADER_OFFSET, VERIFY_LEN); #endif writeFlash(TP_HEADER_OFFSET, (uint8_t*)header_bak, VERIFY_LEN); /* TP_HEADER_LEN < VERIFY_LEN */ header = header_bak; } } VF_DBG("validate local firmware...\nTP Header at %p", header); if (0 == skipValidate) //如果不跳过校验,调用 validatePartitions() 校验指定分区;如果校验成功,标记为已验证,并将 header 写入备份区域。 { ret = validatePartitions(header, partitions); if (0 == ret) { header->isVerified = 1; VF_DBG("validatePartitions Success, try to write verify\n"); #ifdef USE_NAND_FLASH eraseFlash(CFG_FLASH_BASE + CFG_FLASH_SIZE - VERIFY_LEN, VERIFY_LEN); #endif writeFlash(CFG_FLASH_BASE + CFG_FLASH_SIZE - VERIFY_LEN, (uint8_t *)header, VERIFY_LEN); } } return ret; }这段代码描述:这个是minios的recover相关 这是什么意思

filetype

cmake_minimum_required(VERSION 3.13) INCLUDE(CheckLibraryExists) INCLUDE(CheckFunctionExists) PROJECT(ubox C) ADD_DEFINITIONS(-Wall -Werror) IF(CMAKE_C_COMPILER_VERSION VERSION_GREATER 6) ADD_DEFINITIONS(-Wextra -Werror=implicit-function-declaration) ADD_DEFINITIONS(-Wformat -Werror=format-security -Werror=format-nonliteral) ENDIF() ADD_DEFINITIONS(-Os -std=gnu99 -g3 -Wmissing-declarations -Wno-unused-parameter) OPTION(BUILD_LUA "build Lua plugin" ON) OPTION(BUILD_EXAMPLES "build examples" ON) INCLUDE(FindPkgConfig) PKG_SEARCH_MODULE(JSONC json-c) IF(JSONC_FOUND) ADD_DEFINITIONS(-DJSONC) INCLUDE_DIRECTORIES(${JSONC_INCLUDE_DIRS}) ENDIF() SET(SOURCES avl.c avl-cmp.c blob.c blobmsg.c uloop.c usock.c ustream.c ustream-fd.c vlist.c utils.c safe_list.c runqueue.c md5.c kvlist.c ulog.c base64.c udebug.c udebug-remote.c) ADD_LIBRARY(ubox SHARED ${SOURCES}) ADD_LIBRARY(ubox-static STATIC ${SOURCES}) SET_TARGET_PROPERTIES(ubox-static PROPERTIES OUTPUT_NAME ubox) SET(LIBS) CHECK_FUNCTION_EXISTS(clock_gettime HAVE_GETTIME) CHECK_FUNCTION_EXISTS(shm_open HAVE_SHM) IF(NOT HAVE_GETTIME OR NOT HAVE_SHM) CHECK_LIBRARY_EXISTS(rt clock_gettime "" NEED_GETTIME) CHECK_LIBRARY_EXISTS(rt shm_open "" NEED_SHM) IF(NEED_GETTIME OR NEED_SHM) TARGET_LINK_LIBRARIES(ubox rt) ENDIF() ENDIF() FILE(GLOB headers *.h) LIST(FILTER headers EXCLUDE REGEX "-priv.h$" ) INSTALL(FILES ${headers} DESTINATION include/libubox ) INSTALL(TARGETS ubox ubox-static ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) ADD_SUBDIRECTORY(lua) ADD_SUBDIRECTORY(examples) MACRO(ADD_UNIT_TEST_SAN name) ADD_EXECUTABLE(${name}-san ${name}.c) TARGET_COMPILE_OPTIONS(${name}-san PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined,address,leak -fno-sanitize-recover=all) TARGET_LINK_OPTIONS(${name}-san PRIVATE -fsanitize=undefined,address,leak) TARGET_LINK_LIBRARIES(${name}-san ubox blobmsg_json json_script ${json}) TARGET_INCLUDE_DIRECTORIES(${name}-san PRIVATE ${PROJECT_SOURCE_DIR}) ENDMACRO(ADD_UNIT_TEST_SAN) IF(UNIT_TESTING) ENABLE_TESTING() ADD_SUBDIRECTORY(tests) ENDIF() find_library(json NAMES json-c) IF(EXISTS ${json}) ADD_LIBRARY(blobmsg_json SHARED blobmsg_json.c) TARGET_LINK_LIBRARIES(blobmsg_json ubox ${json}) ADD_LIBRARY(blobmsg_json-static STATIC blobmsg_json.c) SET_TARGET_PROPERTIES(blobmsg_json-static PROPERTIES OUTPUT_NAME blobmsg_json) IF(UNIT_TESTING) ADD_UNIT_TEST_SAN(jshn) ENDIF(UNIT_TESTING) ADD_EXECUTABLE(jshn jshn.c) TARGET_LINK_LIBRARIES(jshn blobmsg_json ${json}) ADD_LIBRARY(json_script SHARED json_script.c) TARGET_LINK_LIBRARIES(json_script ubox) INSTALL(TARGETS blobmsg_json blobmsg_json-static jshn json_script ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin ) FILE(GLOB scripts sh/*.sh) INSTALL(FILES ${scripts} DESTINATION share/libubox ) ENDIF() IF(ABIVERSION) SET_TARGET_PROPERTIES(ubox PROPERTIES VERSION ${ABIVERSION}) SET_TARGET_PROPERTIES(json_script PROPERTIES VERSION ${ABIVERSION}) SET_TARGET_PROPERTIES(blobmsg_json PROPERTIES VERSION ${ABIVERSION}) ENDIF() Cmakelist文件如上

filetype

/** * @brief EFM program (single program mode). * @param [in] u32Addr The specified program address. * @param [in] pu8Buf The pointer of specified program data. * @param [in] u32Len The length of specified program data. * @retval int32_t: * - LL_OK: Program successful. * - LL_ERR_NOT_RDY: EFM if not ready. * @note Call EFM_REG_Unlock() unlock EFM register first. */ int32_t EFM_Program(uint32_t u32Addr, const uint8_t *pu8Buf, uint32_t u32Len) { int32_t i32Ret = LL_OK; uint32_t u32Tmp; uint8_t u8Shift; uint32_t u32LoopWords = u32Len >> 2UL; uint32_t u32RemainBytes = u32Len % 4UL; uint32_t *u32pSource = (uint32_t *)(uint32_t)pu8Buf; uint32_t *u32pDest = (uint32_t *)u32Addr; uint32_t u32LastWord; DDL_ASSERT(IS_EFM_REG_UNLOCK()); DDL_ASSERT(IS_EFM_FWMC_UNLOCK()); DDL_ASSERT(IS_EFM_ADDR(u32Addr)); DDL_ASSERT(IS_EFM_ADDR(u32Addr + u32Len - 1UL)); DDL_ASSERT(IS_ADDR_ALIGN_WORD(u32Addr)); u8Shift = 0U; /* Clear the error flag. */ EFM_ClearStatus(EFM_FLAG_ALL); /* Get CACHE status */ u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL); /* Disable CACHE */ CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL); /* Set single program mode. */ MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SINGLE); while ((u32LoopWords-- > 0UL) && (LL_OK == i32Ret)) { /* program data. */ *u32pDest++ = *u32pSource++; /* Wait operate end. */ i32Ret = EFM_WaitEnd(u8Shift, EFM_PGM_TIMEOUT); } if ((0U != u32RemainBytes) && (LL_OK == i32Ret)) { u32LastWord = *u32pSource; u32LastWord |= 0xFFFFFFFFUL << (u32RemainBytes * 8UL); *u32pDest++ = u32LastWord; /* Wait operate end. */ i32Ret = EFM_WaitEnd(u8Shift, EFM_PGM_TIMEOUT); } /* Set read only mode. */ MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY); /* Recover CACHE function */ MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp); return i32Ret; } /** * @brief EFM single program mode(Word). * @param [in] u32Addr The specified program address. * @param [in] u32Data The specified program data. * @retval int32_t: * - LL_OK: Program successfully * - LL_ERR_NOT_RDY: EFM is not ready. * @note Call EFM_REG_Unlock() unlock EFM register first. */ int32_t EFM_ProgramWord(uint32_t u32Addr, uint32_t u32Data) { int32_t i32Ret; uint32_t u32Tmp; uint8_t u8Shift; DDL_ASSERT(IS_EFM_REG_UNLOCK()); DDL_ASSERT(IS_EFM_FWMC_UNLOCK()); DDL_ASSERT(IS_EFM_ADDR(u32Addr)); DDL_ASSERT(IS_ADDR_ALIGN_WORD(u32Addr)); /* Clear the error flag. */ EFM_ClearStatus(EFM_FLAG_ALL); /* Get CACHE status */ u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL); /* Disable CACHE function */ CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL); u8Shift = 0U; /* Set single program mode. */ MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SINGLE); /* Program data. */ RW_MEM32(u32Addr) = u32Data; /* Wait operate end. */ i32Ret = EFM_WaitEnd(u8Shift, EFM_PGM_TIMEOUT); /* Set read only mode. */ MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY); /* Recover CACHE function */ MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp); return i32Ret; }

filetype

帮我分析一下这段recover代码的流程 #include <common.h> #include <command.h> #include "md5.h" #define ERR_NONE 0 #define ERR_GENERIC -1 #define ERR_RSA_CHECK_FAIL -2 #define ERR_HWID_NOT_FOUND -3 #define ERR_FWID_NOT_FOUND -4 #define ERR_HWID_NOT_SUPPORTED -5 #define ERR_FWID_NOT_SUPPORTED -6 #define ERR_PARTITION_TYPE_NOT_SUPPORTED -7 #define ERR_INCORRECT_FILE_SIZE -8 #define ERR_READ_FLASH -9 #define ERR_WRITE_FLASH -10 #define ERR_ERASE_FLASH -11 #define ERR_BAD_ADDRESS -12 #define ERR_MEMORY_ALLOC -13 #define ERR_INVALID_TP_HEADER -14 #define ERR_PARTITION_VALIDATION_FAILED -15 #define CFG_FLASH_BASE (0x0) #define DEFAULT_8MB_FLASH_SIZE (8*1024*1024) #ifndef FLASH_SIZE_IN_MB #define CFG_FLASH_SIZE (DEFAULT_8MB_FLASH_SIZE) #else #define CFG_FLASH_SIZE (FLASH_SIZE_IN_MB*1024*1024) #endif #define CFG_FLASH_SECTOR_SIZE (64*1024) #ifdef CONFIG_LOADADDR #undef CONFIG_LOADADDR #endif #define CONFIG_LOADADDR 0x22100000 /* Flash layout constants. */ #ifndef FACTORY_BOOT_OFFSET #define FACTORY_BOOT_OFFSET 0x0 #endif #ifndef FACTORY_BOOT_LEN #define FACTORY_BOOT_LEN 0x0001F000 #endif #ifndef FACTORY_INFO_OFFSET #define FACTORY_INFO_OFFSET (FACTORY_BOOT_OFFSET + FACTORY_BOOT_LEN) #endif #ifndef FACTORY_INFO_LEN #define FACTORY_INFO_LEN 0x00001000 #endif #ifdef ENABLE_ISP_PARTITION #ifndef RADIO_OFFSET #define RADIO_OFFSET (FACTORY_INFO_OFFSET + FACTORY_INFO_LEN) #endif #ifndef RADIO_LEN #define RADIO_LEN 0x10000 #endif #ifndef UC_OFFSET #define UC_OFFSET (RADIO_OFFSET + RADIO_LEN) #endif #else #ifndef UC_OFFSET #define UC_OFFSET (FACTORY_INFO_OFFSET + FACTORY_INFO_LEN) #endif #endif #ifndef UC_LEN #define UC_LEN 0x10000 #endif #ifndef BOOTLOADER_OFFSET #define BOOTLOADER_OFFSET (UC_OFFSET + UC_LEN) #endif #ifndef BOOTLOADER_LEN #define BOOTLOADER_LEN 0x10000 #endif #ifndef TP_HEADER_OFFSET #define TP_HEADER_OFFSET (BOOTLOADER_OFFSET + BOOTLOADER_LEN) #endif #ifndef TP_HEADER_LEN #define TP_HEADER_LEN 0x200 #endif #ifndef KERNEL_ROMFS_OFFSET #define KERNEL_ROMFS_OFFSET (TP_HEADER_OFFSET + TP_HEADER_LEN) #endif //===================================================== #define KERNEL_OFFSET KERNEL_ROMFS_OFFSET //======================================================= #ifdef USE_NAND_FLASH #define VERIFY_LEN 0x20000 #else #define VERIFY_LEN 0x10000 #endif #ifndef JFFS2_OFFSET #define ROOTFS_DATA_OFFSET ((CFG_FLASH_SIZE + TP_HEADER_OFFSET - VERIFY_LEN) / 2) #define ROOTFS_DATA_SIZE ((CFG_FLASH_SIZE - TP_HEADER_OFFSET - VERIFY_LEN) / 2) #endif #define MD5SUM_LEN 16 #define FW_ID_LEN 16 /* content type flags. */ #define CONTENT_TYPE_BOOTLOADER 0x0001 #define CONTENT_TYPE_KERNEL 0x0002 #define CONTENT_TYPE_ROMFS 0x0004 #define CONTENT_TYPE_JFFS2FS 0x0008 /* partition type flags. */ #define PARTITION_TYPE_BOOTLOADER CONTENT_TYPE_BOOTLOADER #define PARTITION_TYPE_KERNEL CONTENT_TYPE_KERNEL //================================================= #define PARTITION_TYPE_ROMFS CONTENT_TYPE_ROMFS //================================================= #define PARTITION_TYPE_ROOTFS_DATA CONTENT_TYPE_JFFS2FS /* define tp header */ #define MAGIC_LEN 20 #define CRC_LEN 16 #define FW_DESC_LEN 12 #if 1 #define VF_DBG(fmt, args...) \ printf("VF: %s: " fmt "\n" , __FUNCTION__ , ## args) #else #define VF_DBG(fmt, args...) do {} while (0) #endif #define ERR(fmt, ...) { \ printf("error: " fmt "\n", \ ## __VA_ARGS__ ); \ } typedef struct _TP_HEADER { unsigned int headerVersion; unsigned char magicNumber[MAGIC_LEN]; unsigned int kernelLoadAddress; unsigned int kernelEntryPoint; unsigned short vendorId; unsigned short zoneCode; unsigned int partitionNum; unsigned int factoryBootOffset; unsigned int factoryBootLen; unsigned int factoryInfoOffset; unsigned int factoryInfoLen; unsigned int radioOffset; unsigned int radioLen; unsigned int ucOffset; unsigned int ucLen; unsigned int bootloaderOffset; unsigned int bootloaderLen; unsigned int tpHeaderOffset; unsigned int tpHeaderLen; unsigned int kernelOffset; unsigned int kernelLen; unsigned int romFsOffset; unsigned int romFsLen; unsigned int jffs2FsOffset; unsigned int jffs2FsLen; unsigned char factoryInfoCRC[CRC_LEN]; unsigned char radioCRC[CRC_LEN]; unsigned char ubootCRC[CRC_LEN]; //unsigned char kernelAndRomfsCRC[CRC_LEN]; //=============================================== unsigned char kernelCRC[CRC_LEN]; unsigned char RomfsCRC[CRC_LEN]; //=============================================== unsigned char fwId[FW_ID_LEN]; unsigned char fwDescription[FW_DESC_LEN]; unsigned int fwIdBLNum; unsigned char fwIdBL[0][FW_ID_LEN]; unsigned char serviceCRC[CRC_LEN]; unsigned int isVerified; unsigned int jffs2RealFsLen; } TP_HEADER; static unsigned char gTpHeaderMagicNumber[MAGIC_LEN] = {0x55, 0xAA, 0x9D, 0xD1, 0xA8, 0xC8, 0x83, 0x31, 0xC9, 0x69, 0xFB, 0xBF, 0xBC, 0xF0, 0xD4, 0x32, 0x70, 0xC7, 0xAA, 0x55}; static int addr_flash(void* addr) { if((unsigned long)addr < 0 || (unsigned long)addr >= CFG_FLASH_SIZE) { printf("%p: Not a valid flash address!", addr); return ERR_BAD_ADDRESS; } return 0; } static int readFlash(uint32_t addrOffset, uint8_t* buf, uint32_t buflen) { int ret = 0; char cmdbuf[70]; //TODO:need to detect address type. ret = addr_flash((void*)addrOffset); if(ret < 0) { return ret; } // ret = addr_mem(buf); // if(ret < 0) // { // return ret; // } #ifdef USE_NAND_FLASH sprintf(cmdbuf, "nand read.e 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen); #else sprintf(cmdbuf, "sf probe 0;sf read 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen); #endif if(run_command(cmdbuf, 0) < 0) { return ERR_READ_FLASH; } return 0; } static int writeFlash(uint32_t addrOffset, uint8_t* buf, uint32_t buflen) { int ret = 0; char cmdbuf[70]; //TODO:need to detect address type. ret = addr_flash((void*)addrOffset); if(ret < 0) { return ret; } // ret = addr_mem(buf); // if(ret < 0) // { // return ret; // } #ifdef USE_NAND_FLASH sprintf(cmdbuf, "nand write.e 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen); #else sprintf(cmdbuf, "sf probe 0;sf erase 0x%x 0x%x;sf write 0x%x 0x%x 0x%x", addrOffset, buflen, (uint32_t)buf, addrOffset, buflen); #endif if(run_command(cmdbuf, 0) < 0) { return ERR_READ_FLASH; } return 0; } /* * Function Name: eraseFlash * Author: CaiBin * Date: 2014-11-07 * Description: Erase flash content of a given flash address. * Parameter: * addrOffset: Flash address to erase. * eraselen: Erase length in bytes. * buflen: Length of the data buf in bytes. * return: * 0: Succeeded; * ERR_ERASE_FLASH: Erase command execution error. * ERR_BAD_ADDRESS: Invalid address values passed. */ static int eraseFlash(uint32_t addrOffset, uint32_t eraselen) { int ret; char cmdbuf[70]; ret = addr_flash((void*)addrOffset); if (ret < 0) { return ret; } //if addr offset or eraselen is not on sector boundary, return err. if (0 != (addrOffset % CFG_FLASH_SECTOR_SIZE)) { ERR("%s: addrOffset is 0x%08x\n, not on sector boundary!", __func__, addrOffset); return ERR_BAD_ADDRESS; } if (0 != (eraselen % CFG_FLASH_SECTOR_SIZE)) { ERR("%s: eraselen is 0x%08x\n, not on sector boundary!", __func__, eraselen); return ERR_BAD_ADDRESS; } //TODO:need to detect address type. #ifdef USE_NAND_FLASH sprintf(cmdbuf, "nand erase 0x%x 0x%x", addrOffset, eraselen); #else sprintf(cmdbuf, "sf probe 0;sf erase 0x%x 0x%x", addrOffset, eraselen); #endif if (run_command(cmdbuf, 0) < 0) { return ERR_ERASE_FLASH; } return 0; } static void debug_print_md5(unsigned char *digest) { int i = 0; for (i = 0; i < 16; i++) printf("%02x", digest[i]); printf("\n"); } static void calcMd5(char *data, int size, char *md5) //计算md5 { MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, data, size); MD5_Final(md5, &ctx); } #ifdef USE_NAND_FLASH /* 参考自 lib_uip/apps/upgrade/http_upgrade.c中的executeUpgrade_nand() */ static int restore_Mini_Main_nand(TP_HEADER *header, unsigned char *base) { int ret = 0; int i =0; printf("execute nand flash restore kernelRom...\n"); /* ntohl(tp_head->tphead_len) + ntohl(tp_head->kernel_len) + ntohl(tp_head->romfs_len) */ /* tp_header, kernel, romFS */ uint32_t offset[] = { TP_HEADER_OFFSET, KERNEL_OFFSET, ntohl(header->romFsOffset) }; uint32_t eraseLen[] = { KERNEL_OFFSET - TP_HEADER_OFFSET, ntohl(header->romFsOffset) - KERNEL_OFFSET, ntohl(header->jffs2FsOffset) - ntohl(header->romFsOffset) }; uint32_t writeLen[] = { TP_HEADER_LEN, ntohl(header->kernelLen), ntohl(header->romFsLen) }; uint8_t* baseArr[] ={ (uint8_t*)base, (uint8_t*)((uint8_t*)base + TP_HEADER_LEN), (uint8_t*)((uint8_t*)base + TP_HEADER_LEN + ntohl(header->kernelLen)) }; for (i = 0; i < sizeof(offset) / sizeof(uint32_t); i++) { ret = eraseFlash(offset[i], eraseLen[i]); if (ret < 0) { goto error_exit; } //start to write firmware. printf("[step%d] write offset: 0x%08x, from: %p, size: 0x%08x\n", i + 1, offset[i], baseArr[i], writeLen[i]); ret = writeFlash(offset[i], baseArr[i], writeLen[i]); if (ret < 0) { goto error_exit; } } return 0; error_exit: ERR("erase or write nand flash failed!"); return ret; } #endif /* * Function Name: validatePartitions * Author: CaiBin * Date: 2014-11-07 * Description: Check valid firmware partitions. * Validate partition offsets,lengths and CRC's in TP Header. * Parameter: * header: Points to the TP Header partition of the firmware image to validate. * return: * 0: Succeeded; * ERR_INVALID_TP_HEADER: Firmware has not all partitions. * ERR_PARTITION_VALIDATION_FAILED: Partition CRC verification failed. */ static int validatePartitions(TP_HEADER* header, uint32_t partition_type) //固件分区校验函数,用于验证固件中多个关键分区(内核、romfs、rootfs 等)的完整性。它通过比较各分区的 MD5 校验值来判断是否损坏,并在必要时尝试从备份区域恢复。 { int ret = 0; // uint32_t kernel_romfs_length = ntohl(header->kernelLen) + ntohl(header->romFsLen); // //array of validation crc's. // unsigned char* crc[] = {header->kernelAndRomfsCRC, header->serviceCRC}; // //array of partition offsets & lengths. // //def JFFS2_OFFSET 代表jffs的分区是自己确定的,else是对半分 // #ifdef JFFS2_OFFSET // #ifdef USE_NAND_FLASH // uint32_t rootfs_data_offset = ntohl(header->jffs2FsOffset); // #else // uint32_t rootfs_data_offset = KERNEL_ROMFS_OFFSET + ntohl(header->kernelLen) + ntohl(header->romFsLen); // #endif // uint32_t offset[] = {KERNEL_ROMFS_OFFSET, rootfs_data_offset}; // uint32_t length[] = {kernel_romfs_length, ntohl(header->jffs2RealFsLen)}; // #else // uint32_t offset[] = {KERNEL_ROMFS_OFFSET, ROOTFS_DATA_OFFSET}; // uint32_t length[] = {kernel_romfs_length, ROOTFS_DATA_SIZE}; // #endif // //array of messages. // char* dbg_msg[] = {"kernel and romfs", "rootfs data"}; // //array of partition type flags to decide which partition to be validated. // uint32_t partition_flags[] = {PARTITION_TYPE_KERNEL, PARTITION_TYPE_ROOTFS_DATA}; //============================================================================================== uint32_t kernel_romfs_length = ntohl(header->kernelLen) + ntohl(header->romFsLen); uint32_t kernel_length = ntohl(header->kernelLen); uint32_t romfs_length = ntohl(header->romFsLen); uint32_t ROMFS_OFFSET = KERNEL_OFFSET + kernel_length; //array of validation crc's. unsigned char* crc[] = {header->kernelCRC, header->RomfsCRC, header->serviceCRC}; //array of partition offsets & lengths. //def JFFS2_OFFSET 代表jffs的分区是自己确定的,else是对半分 #ifdef JFFS2_OFFSET //删除了nandflash uint32_t rootfs_data_offset = KERNEL_ROMFS_OFFSET + ntohl(header->kernelLen) + ntohl(header->romFsLen); uint32_t offset[] = {KERNEL_OFFSET, ROMFS_OFFSET, rootfs_data_offset}; uint32_t length[] = {kernel_length, romfs_length, ntohl(header->jffs2RealFsLen)}; #else uint32_t offset[] = {KERNEL_OFFSET, ROMFS_OFFSET, ROOTFS_DATA_OFFSET}; uint32_t length[] = {kernel_length, romfs_length, ROOTFS_DATA_SIZE}; #endif //array of messages. char* dbg_msg[] = {"kernel", "romfs", "rootfs data"}; //array of partition type flags to decide which partition to be validated. uint32_t partition_flags[] = {PARTITION_TYPE_KERNEL, PARTITION_TYPE_ROMFS, PARTITION_TYPE_ROOTFS_DATA}; unsigned char md5Tmp[MD5SUM_LEN] = {0}; unsigned char md5RootfsData[MD5SUM_LEN] = {0}; unsigned char md5BackKernData[MD5SUM_LEN] = {0}; unsigned char md5BackRomData[MD5SUM_LEN] = {0}; unsigned char* base = NULL; int i; //=============================================================================================== // unsigned char md5Tmp[MD5SUM_LEN] = {0}; // unsigned char md5RootfsData[MD5SUM_LEN] = {0}; // unsigned char* base = NULL; // int i; VF_DBG("Validating partitions..."); /* 检查tpheader中的偏移量和长度数据是否正确 */ VF_DBG("Factory Boot Offset: %x, Length: %x", ntohl(header->factoryBootOffset), ntohl(header->factoryBootLen)); if(ntohl(header->factoryBootOffset) != FACTORY_BOOT_OFFSET || ntohl(header->factoryBootLen) != FACTORY_BOOT_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("Factory Info Offset: %x, Length: %x", ntohl(header->factoryInfoOffset), ntohl(header->factoryInfoLen)); if(ntohl(header->factoryInfoOffset) != FACTORY_INFO_OFFSET || ntohl(header->factoryInfoLen) != FACTORY_INFO_LEN) { return ERR_INVALID_TP_HEADER; } #ifdef ENABLE_ISP_PARTITION VF_DBG("Radio Offset: %x, Length: %x", ntohl(header->radioOffset), ntohl(header->radioLen)); if(ntohl(header->radioOffset) != RADIO_OFFSET || ntohl(header->radioLen) != RADIO_LEN) { return ERR_INVALID_TP_HEADER; } #endif VF_DBG("User Config Offset: %x, Length: %x", ntohl(header->ucOffset), ntohl(header->ucLen)); if(ntohl(header->ucOffset) != UC_OFFSET || ntohl(header->ucLen) != UC_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("UBoot Offset: %x, Length: %x", ntohl(header->bootloaderOffset), ntohl(header->bootloaderLen)); if(ntohl(header->bootloaderOffset) != BOOTLOADER_OFFSET || ntohl(header->bootloaderLen) != BOOTLOADER_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("TP Header Offset: %x, Length: %x", ntohl(header->tpHeaderOffset), ntohl(header->tpHeaderLen)); if(ntohl(header->tpHeaderOffset) != TP_HEADER_OFFSET || ntohl(header->tpHeaderLen) != TP_HEADER_LEN) { return ERR_INVALID_TP_HEADER; } VF_DBG("Kernel Offset: %x, Length: %x", ntohl(header->kernelOffset), ntohl(header->kernelLen)); #ifndef USE_NAND_FLASH if (ntohl(header->kernelOffset) != KERNEL_ROMFS_OFFSET) #else if (ntohl(header->kernelOffset) != KERNEL_OFFSET) #endif { return ERR_INVALID_TP_HEADER; } VF_DBG("Romfs Offset: %x, Length: %x", ntohl(header->romFsOffset), ntohl(header->romFsLen)); VF_DBG("JFFS2 Offset: %x, Length: %x", ntohl(header->jffs2FsOffset), ntohl(header->jffs2FsLen)); #ifndef USE_NAND_FLASH /* It is not true for nand, because there are gaps in kernel and romFS partitions */ if(ntohl(header->kernelLen) + ntohl(header->romFsLen) + ntohl(header->jffs2FsLen)+ VERIFY_LEN + KERNEL_ROMFS_OFFSET #ifdef MTD_USER_RECORD_PARTS + USER_RECORD_PARTITION_LEN #endif != CFG_FLASH_SIZE) { return ERR_INVALID_TP_HEADER; } #endif //verifying partition CRC. base = (char *)CONFIG_LOADADDR; // for (i = 0; i < sizeof(crc) / sizeof(char *); i++) // { // if (partition_type & partition_flags[i]) // { // VF_DBG("verifying %s partition [0x%x,0x%x]...", dbg_msg[i], offset[i], length[i]); // memset(md5Tmp, 0, MD5SUM_LEN); // VF_DBG("base: %p, offset: %p, length: %x", base, base + offset[i], (int)length[i]); // calcMd5((char *)(base + offset[i]), (int)length[i], (char *)md5Tmp); //读取 Flash 数据到内存,计算 MD5 // // debug_print_md5(md5Tmp); // // debug_print_md5(crc[i]); // if (memcmp(md5Tmp, crc[i], MD5SUM_LEN) == 0) //与 header 中的原始 MD5 对比; // { // VF_DBG("ok"); // } // else // { // VF_DBG("failed"); // /* 固件kernel&RomFS损坏, 尝试从JFFS2恢复 */ // if (ERR_PARTITION_VALIDATION_FAILED == ret && partition_flags[i] == PARTITION_TYPE_ROOTFS_DATA) //循环到第二个 // { // #ifdef USE_NAND_FLASH // calcMd5((char *)(base + TP_HEADER_LEN), (int)kernel_romfs_length, (char *)md5RootfsData); // #else // #ifdef JFFS2_OFFSET // calcMd5((char *)(base + rootfs_data_offset + TP_HEADER_LEN), kernel_romfs_length, md5RootfsData); // #else // calcMd5((char *)(base + ROOTFS_DATA_OFFSET + TP_HEADER_LEN), kernel_romfs_length, md5RootfsData); //从 JFFS2 中计算出 MD5 值,用于后续恢复操作。 // #endif // #endif // } // ret = ERR_PARTITION_VALIDATION_FAILED; // } // } // } // if (ERR_PARTITION_VALIDATION_FAILED == ret) // { // if (memcmp(md5RootfsData, header->kernelAndRomfsCRC, MD5SUM_LEN) == 0) // { // printf("restore kernelAndRomfs\n"); // #ifdef USE_NAND_FLASH // restore_Mini_Main_nand(header, base); // #else // #ifdef JFFS2_OFFSET // writeFlash(TP_HEADER_OFFSET, base + rootfs_data_offset, ntohl(header->tpHeaderLen) + kernel_romfs_length); // #else // writeFlash(TP_HEADER_OFFSET, base + ROOTFS_DATA_OFFSET, ROOTFS_DATA_SIZE); // #endif // #endif // } // } // return ret; // } //========================================================================================================================== int restore_kernel_flag = 0; int restore_romfs_flag = 0; int brokenPart = 0; // 用于记录当前处理的分区索引 for (i = 0; i < sizeof(crc) / sizeof(char *); i++) { if (partition_type & partition_flags[i]) { VF_DBG("verifying %s partition [0x%x,0x%x]...", dbg_msg[i], offset[i], length[i]); //删除nandflash部分 memset(md5Tmp, 0, MD5SUM_LEN); VF_DBG("base: %p, offset: %p, length: %x", base, base + offset[i], (int)length[i]); calcMd5((char *)(base + offset[i]), (int)length[i], (char *)md5Tmp); if (memcmp(md5Tmp, crc[i], MD5SUM_LEN) == 0) { VF_DBG("ok"); } else { VF_DBG("failed"); brokenPart = i; // 记录当前失败分区索引 // Kernel分区验证失败时检查RomFS中的备份 if (0 == brokenPart) // 第一个分区(kernel) { VF_DBG("Checking kernel backup in RomFS..."); memset(md5BackKernData, 0, MD5SUM_LEN); calcMd5((char *)(base + ROMFS_OFFSET + TP_HEADER_LEN), kernel_length, md5BackKernData); if (memcmp(md5BackKernData, crc[i] , MD5SUM_LEN) == 0) { restore_kernel_flag = 1; VF_DBG("Kernel backup in RomFS is good"); } } // RomFS分区验证失败时检查JFFS中的备份 if (1 == brokenPart) // 第二个分区(romfs) { VF_DBG("Checking romfs backup in JFFS..."); memset(md5BackRomData, 0, MD5SUM_LEN); #ifdef JFFS2_OFFSET calcMd5((char *)(base + rootfs_data_offset), romfs_length, md5BackRomData); #else calcMd5((char *)(base + ROOTFS_DATA_OFFSET), romfs_length, md5BackRomData); #endif if (memcmp(md5BackRomData, crc[i], MD5SUM_LEN) == 0) { restore_romfs_flag = 1; VF_DBG("Romfs backup in JFFS is good"); } } ret = ERR_PARTITION_VALIDATION_FAILED; } } } if (ERR_PARTITION_VALIDATION_FAILED == ret) { // 从RomFS分区恢复Kernel if (restore_kernel_flag) { VF_DBG("Restoring kernel from RomFS backup..."); writeFlash(TP_HEADER_OFFSET, base + ROMFS_OFFSET, kernel_length);//备份时tpheader和ker在一起 } // 从JFFS分区恢复RomFS if (restore_romfs_flag) { VF_DBG("Restoring romfs from JFFS backup..."); #ifdef JFFS2_OFFSET writeFlash(ROMFS_OFFSET, base + rootfs_data_offset, romfs_length); #else writeFlash(ROMFS_OFFSET, base + ROOTFS_DATA_OFFSET, romfs_length); #endif } } return ret; } //========================================================================================================================== static int checkTpHeaderMagicNumber(TP_HEADER* header) { int i; if (memcmp(gTpHeaderMagicNumber, header->magicNumber, MAGIC_LEN) == 0) { return 0; } else { return 1; } } int validateFirmwareWithRecover(void) { int ret = 0; unsigned char skipValidate = 0; TP_HEADER* header = NULL; TP_HEADER* header_bak = NULL; //uint32_t partitions = PARTITION_TYPE_KERNEL | PARTITION_TYPE_ROOTFS_DATA; //======================================================================================= uint32_t partitions = PARTITION_TYPE_KERNEL | PARTITION_TYPE_ROMFS | PARTITION_TYPE_ROOTFS_DATA; //====================================================================================== //return ERR_PARTITION_VALIDATION_FAILED;// skip validate for test #ifdef USE_NAND_FLASH /* read tp_header to RAM */ ret = readFlash(TP_HEADER_OFFSET, (uint8_t*)CONFIG_LOADADDR, TP_HEADER_LEN); if (ret < 0) { ERR("reading nandflash tp_head to RAM failed."); return ret; } /* read tp_header_bak (verify) to RAM * don't take into account for not MINI_MAIN **/ ret = readFlash(CFG_FLASH_BASE + CFG_FLASH_SIZE - VERIFY_LEN, (uint8_t*)(CONFIG_LOADADDR + TP_HEADER_LEN), TP_HEADER_LEN); if (ret < 0) { ERR("reading nandflash tp_head_bak to RAM failed."); return ret; } header = (TP_HEADER*)(CONFIG_LOADADDR); header_bak = (TP_HEADER*)(CONFIG_LOADADDR + TP_HEADER_LEN); #else /* copy whole flash image to RAM. */ VF_DBG("copying flash to 0x%x", CONFIG_LOADADDR); ret = readFlash(0, CONFIG_LOADADDR, CFG_FLASH_SIZE); if (ret < 0) { printf("reading flash to RAM failed."); return ret; } VF_DBG("ret=%d(%p)", ret, &ret); header = (TP_HEADER*)(CONFIG_LOADADDR + TP_HEADER_OFFSET); header_bak = (TP_HEADER*)(CONFIG_LOADADDR + CFG_FLASH_SIZE - VERIFY_LEN); #endif if (checkTpHeaderMagicNumber(header_bak)) //如果备份 header 的 Magic Number 不合法,则设为 NULL; { header_bak = NULL; //如果备份 header 的 isVerified 字段为 1,表示已验证过,跳过校验。 } else if (header_bak->isVerified == 1){ skipValidate = 1; } if (checkTpHeaderMagicNumber(header)) //如果主 header 损坏,但备份 header 有效;则擦除主 header 所在区域,将备份写入 { if (header_bak) { printf("restore tpHeader\n"); #ifdef USE_NAND_FLASH eraseFlash(TP_HEADER_OFFSET, VERIFY_LEN); #endif writeFlash(TP_HEADER_OFFSET, (uint8_t*)header_bak, VERIFY_LEN); /* TP_HEADER_LEN < VERIFY_LEN */ header = header_bak; } } VF_DBG("validate local firmware...\nTP Header at %p", header); if (0 == skipValidate) //如果不跳过校验,调用 validatePartitions() 校验指定分区;如果校验成功,标记为已验证,并将 header 写入备份区域。 { ret = validatePartitions(header, partitions); if (0 == ret) { header->isVerified = 1; VF_DBG("validatePartitions Success, try to write verify\n"); #ifdef USE_NAND_FLASH eraseFlash(CFG_FLASH_BASE + CFG_FLASH_SIZE - VERIFY_LEN, VERIFY_LEN); #endif writeFlash(CFG_FLASH_BASE + CFG_FLASH_SIZE - VERIFY_LEN, (uint8_t *)header, VERIFY_LEN); } } return ret; }

filetype

#include <stdio.h> #include <stdlib.h> #include <libgen.h> #include <unistd.h> #include <time.h> #include <errno.h> #include <dirent.h> #include "mkbcfw.h" #include "md5.h" #include "ini_parser.h" #define MODEL_FILE_NAME_SIZE (64) static char* progName = NULL; static char* upPrefix = NULL; static int gUpbootBuildTimes = -1; /* -1 means default, 0 means only to build 1 upboot.bin, 1 means no more upboot.bin */ static unsigned short uhTagLength = UPGRADE_HEADER_LEN; static unsigned int hwIdNum = 0; static unsigned int fwIdFLNum = 0; static unsigned int fwIdBLNum = 0; static unsigned int oemIdNum = 0; static unsigned char hwIdListArr[HWID_MAX_NUM][HW_ID_LEN]; static unsigned char fwIdBLArr[FWID_BL_MAX_NUM][FW_ID_LEN]; static unsigned char fwIdFLArr[FWID_FL_MAX_NUM_WIDE][FW_ID_LEN]; static unsigned char oemIdArr[OEMID_MAX_NUM][OEM_ID_LEN]; static char hwIdListIndexStr[GENERATED_INDEX_LIST_STR_MAXLEN]; static char fwIdFLIndexStr[GENERATED_INDEX_LIST_STR_MAXLEN]; static char fwIdBLIndexStr[GENERATED_INDEX_LIST_STR_MAXLEN]; static char oemIdIndexStr[GENERATED_INDEX_LIST_STR_MAXLEN]; static char *gDefaultFactoryInfoFmt = "{\"mac\":\"00-00-00-00-00-00\"," "\"pin\":\"\"," "\"devId\":\"\"," "\"hwId\":\"%s\"," "\"hwIdDes\":\"\"," "\"flashSign\":\"\"," "\"devName\":\"%s\"," "\"hwVer\":\"%s\"," "\"QRCode\":\"\"," "\"testInfo\":\"\"," "\"focalLength\":\"\"," "\"codecType\":\"\"," "\"oemId\":\"%s\"," "\"region\":\"%s\"}"; static unsigned short fInfoDataLength = 0; static unsigned char fInfoMagicNumber[] = {0x4d, 0x31, 0x43, 0x54}; static unsigned char fInfoVersion[] = {0x0, 0x2}; static MODEL_CONFIG mc = {0}; /* store config parsed from conf files */ static MODEL_INFO mi = {0}; /* store info got from input bin files */ static FILE_INFO bootloaderInfo; static FILE_INFO factoryInfo; static FILE_INFO tagInfo; static FILE_INFO versionFileInfo; static FILE_INFO deviceFileInfo; static FILE_INFO fwListFileInfo; static FILE_INFO buildTimeInfo; static FILE_INFO buildrootFileInfo; static FILE_INFO ucFileInfo; static FILE_INFO kernelInfo; static FILE_INFO rootfsInfo; static FILE_INFO recoveryFileInfo; static FILE_INFO serviceFileInfo; static FILE_INFO objdetModelFileInfo[16]; static unsigned char fwID[FW_ID_LEN] = {0}; static char* revStr = NULL; static char* prefix = NULL; static char* layoutId = NULL; static FLASH_LAYOUT *layout; static char gSwVer[SW_VER_LEN] = {0}; static char* gStagingHostDir = NULL; static int gSquashfsBlocksize = 0; static int gFlash2Size = 0; static char* gDetModelsDir = NULL; static int gDetModelsNum = 0; static int gDetModelsSizeSum = 0; static int gDetModelsInFlash2 = 0; static char* gSocType = "T41"; static char* gTagUpAddUserinfo = 0; static FLASH_LAYOUT layouts[] = { { .id = "4M", .flashSize = 0x400000, }, { .id = "4Mlzma", .flashSize = 0x400000, }, { .id = "8M", .flashSize = 0x800000, }, { .id = "8Mlzma", .flashSize = 0x800000, }, { .id = "16M", .flashSize = 0x1000000, }, { .id = "16Mlzma", .flashSize = 0x1000000, }, { .id = "32M", .flashSize = 0x2000000, }, { .id = "32Mlzma", .flashSize = 0x2000000, }, { .id = "128Mlzma", .flashSize = 0x8000000, }, { /* terminating entry */ } }; static FIRMWARE_INFO firmwares[] = { { .binType = "up_boot.bin", .formatName = "%s_%s_%s_up_boot.bin", .contentParts = (CONTENT_TYPE_BOOTLOADER | CONTENT_TYPE_KERNEL | CONTENT_TYPE_ROMFS | CONTENT_TYPE_JFFS2FS), }, { .binType = "flash.bin", .formatName = "%s_%s_%s_flash.bin", .contentParts = (CONTENT_TYPE_BOOTLOADER | CONTENT_TYPE_KERNEL | CONTENT_TYPE_ROMFS | CONTENT_TYPE_JFFS2FS), }, { .binType = "flash2.bin", .formatName = "%s_%s_%s_flash2.bin", .contentParts = (CONTENT_TYPE_BOOTLOADER | CONTENT_TYPE_KERNEL | CONTENT_TYPE_ROMFS | CONTENT_TYPE_JFFS2FS), }, { /* terminating entry */ } }; static FLASH_LAYOUT *getLayout(char *id) { FLASH_LAYOUT *ret; FLASH_LAYOUT *l; ret = NULL; for (l = layouts; l->id != NULL; l++) { if (strcasecmp(id, l->id) == 0) { ret = l; break; } }; return ret; } static int checkOptions() { if (NULL == prefix) { ERR("model prefix name not specified"); return -1; } if (NULL == revStr) { ERR("model revision not specified"); return -1; } if (NULL == layoutId) { ERR("flash layout is not specified"); return -1; } layout = getLayout(layoutId); if (NULL == layout) { ERR("unknown flash layout \"%s\"", layoutId); return -1; } if (!strcmp(gSocType,"T23")) { if (gFlash2Size) { ERR("T23 not support two flash"); gFlash2Size = 0; } } if (!strcmp(gSocType,"PRJ007ZL")) { if (gFlash2Size) { ERR("PRJ007ZL not support two flash"); gFlash2Size = 0; } } DBG("flash2 size: %d", gFlash2Size); DBG("check options done."); return 0; } static int parseVersionFile(const char *filePath) { FILE* fp = NULL; int assigns = 0; unsigned int tmp = 0; int hasSwRev = 0; int hasSwRevMinor = 0; unsigned char lineBuf[CONFIG_FILE_LINE_MAXLEN] = {0}; unsigned char val[CONFIG_FILE_LINE_MAXLEN] = {0}; unsigned char key[CONFIG_FILE_LINE_MAXLEN] = {0}; fp = fopen(filePath, "r"); if (!fp) { ERR("error when open version file"); return EXIT_FAILURE; } while (!feof(fp) && (fgets(lineBuf, CONFIG_FILE_LINE_MAXLEN, fp) != NULL)) { assigns = sscanf(lineBuf, "%s = %[^\t\r\n]", key, val); if (assigns != 2) { continue; } if (strcasecmp(key, "SYS_SOFTWARE_REVISION") == 0) { sscanf(val, "%x", &tmp); mc.major = (tmp & 0xFF00) >> 8; mc.minor = tmp & 0xFF; hasSwRev = 1; } else if (strcasecmp(key, "SYS_SOFTWARE_REVISION_MINOR") == 0) { sscanf(val, "%x", &tmp); mc.revision = tmp & 0xFF; hasSwRevMinor = 1; } } fclose(fp); if (!hasSwRev || !hasSwRevMinor) { ERR("values in version config file are not enough"); return EXIT_FAILURE; } else { return EXIT_SUCCESS; } } static int parseBuildTimeFile(const char* filePath) { struct stat astat; struct tm* tm; if (stat(filePath, &astat)) { ERR("error when stat build time file"); exit(EXIT_FAILURE); } tm = localtime(&astat.st_mtime); mc.year = tm->tm_year % 100; /* tm_year is the number from 1900 */ mc.month = tm->tm_mon + 1; /* tm_mon ranges from 0 to 11 */ mc.day = tm->tm_mday; return 0; } static int parseModelFiles() { int len; int i; char *p; char *p2; DIR *dirp; struct dirent *dp; if (!gDetModelsDir) { return 0; } dirp = opendir(gDetModelsDir); while((dp = readdir(dirp)) != NULL) { if (strcmp(".", dp->d_name) && strcmp("..", dp->d_name)) { objdetModelFileInfo[gDetModelsNum].fileName = malloc(strlen(gDetModelsDir) + strlen(dp->d_name) + 1); sprintf(objdetModelFileInfo[gDetModelsNum].fileName, "%s%s", gDetModelsDir, dp->d_name); gDetModelsNum++; } } if (gDetModelsNum > 16) { printf("model bin num too large > 16\n"); return EXIT_FAILURE; } return 0; } static int str2hex(unsigned char *hexBuf, unsigned char* strBuf) { int ret = EXIT_FAILURE; int i = 0; unsigned char* strPtr; unsigned char strArr[3] = {'\0'}; if (hexBuf == NULL || strBuf == NULL) { goto out; } strPtr = strBuf; while (*strPtr != '\0') { strArr[0] = *strPtr; strArr[1] = *(++strPtr); hexBuf[i] = (unsigned char)strtoul(strArr, NULL, 16); i++; strPtr++; } ret = EXIT_SUCCESS; out: return ret; } static int hex2str(unsigned char *hexBuf, int hexLen, unsigned char* strBuf, int strBufSize) { int ret = EXIT_FAILURE; int i = 0; if (hexBuf == NULL || strBuf == NULL || hexLen <= 0 || strBufSize <= 0 || strBufSize < (hexLen * 2 + 1)) { goto out; } memset(strBuf, 0, strBufSize); for (i = 0; i < hexLen; i++) { snprintf(strBuf + strlen(strBuf), strBufSize - strlen(strBuf), "%02X", hexBuf[i]); } ret = EXIT_SUCCESS; out: return ret; } int parseOneList(INI_CONFIG* config, const char* _sectionName, const char* idOpt, const char* onoffOpt, char* list, int* pIdNum, int idLen, int maxIdNum, char* indexStr, int indexStrMaxLen) { int i = 1; int ret = 0; char sectionName[50] = {0}; char *inListBoolStr = NULL; char *id = NULL; int bInList = 0; int leftLen = 0; memset(indexStr, 0, indexStrMaxLen); /* for loop exit when List is full or no more ID is available */ for (i = 1, *pIdNum = 0; *pIdNum < maxIdNum; i++) { snprintf(sectionName, 50, "%s %d", _sectionName, i); ret = ini_config_bool_section_exist(config, sectionName); if (0 == ret) /* no more firmare section */ { break; } id = ini_config_get_string(config, sectionName, idOpt, NULL); if (NULL == id) { ERR("firmware option '%s' not exist", idOpt); return -1; } inListBoolStr = ini_config_get_string(config, sectionName, onoffOpt, NULL); if (strcasecmp(inListBoolStr, CONF_PUT_IN_LIST_TRUE) && strcasecmp(inListBoolStr, CONF_PUT_IN_LIST_FALSE)) { ERR("firmware option '%s' not exist or wrong", onoffOpt); return -1; } else { bInList = (strcasecmp(inListBoolStr, CONF_PUT_IN_LIST_TRUE) == 0) ? 1 : 0; if (bInList) { ret = str2hex(list + (*pIdNum * idLen), id); if (ret) { return -1; } (*pIdNum)++; /* add index to tail */ leftLen = indexStrMaxLen - strlen(indexStr); ret = snprintf(indexStr + strlen(indexStr), leftLen, "%d ", i); if (ret < 0 || ret >= leftLen) { ERR("snprintf error or truncated"); return -1; } } } } return 0; } int parseFwListFile(const char* filePath) { int ret = EXIT_FAILURE; int maxIdNum = 0; INI_CONFIG *config; config = ini_config_create_from_file(filePath, 0); if (NULL == config) { ERR("firmware config file parser init failed"); goto out; } memset(hwIdListIndexStr, 0, HW_ID_LEN); maxIdNum = HWID_MAX_NUM; ret = parseOneList(config, CONF_HW_SECTION, CONF_HWID_OPTION, CONF_SUPPORTED_OPTION, (unsigned char*)hwIdListArr, &hwIdNum, HW_ID_LEN, maxIdNum, hwIdListIndexStr, sizeof(hwIdListIndexStr)); if (ret) { goto out; } memset(fwIdFLIndexStr, 0, FW_ID_LEN); maxIdNum = (UPGRADE_HEADER_LEN == uhTagLength ? FWID_FL_MAX_NUM : FWID_FL_MAX_NUM_WIDE); ret = parseOneList(config, CONF_FW_SECTION, CONF_FWID_OPTION, CONF_INFL_OPTION, (unsigned char*)fwIdFLArr, &fwIdFLNum, FW_ID_LEN, maxIdNum, fwIdFLIndexStr, sizeof(fwIdFLIndexStr)); if (ret) { goto out; } memset(fwIdBLIndexStr, 0, FW_ID_LEN); maxIdNum = FWID_BL_MAX_NUM; ret = parseOneList(config, CONF_FW_SECTION, CONF_FWID_OPTION, CONF_INBL_OPTION, (unsigned char*)fwIdBLArr, &fwIdBLNum, FW_ID_LEN, maxIdNum, fwIdBLIndexStr, sizeof(fwIdBLIndexStr)); if (ret) { goto out; } memset(oemIdIndexStr, 0, OEM_ID_LEN); maxIdNum = (UPGRADE_HEADER_LEN == uhTagLength ? OEMID_MAX_NUM : OEMID_MAX_NUM_WIDE); ret = parseOneList(config, CONF_OEMID_SECTION, CONF_OEMID_OPTION, CONF_SUPPORTED_OPTION, (unsigned char*)oemIdArr, &oemIdNum, OEM_ID_LEN, maxIdNum, oemIdIndexStr, sizeof(oemIdIndexStr)); if (ret) { goto out; } /* check if has no HwID */ if (0 == hwIdNum) { ret = EXIT_FAILURE; ERR("No HwID supported"); goto out; } /* check if HWIDs and FLIDs are too many to fill upgrade header */ maxIdNum = (UPGRADE_HEADER_LEN == uhTagLength ? UH_ID_MAX_NUM : UH_ID_MAX_NUM_WIDE); if (hwIdNum + fwIdFLNum + oemIdNum > maxIdNum) { ret = EXIT_FAILURE; ERR("HwIDs and FwFLIDs are too many for upgrade header"); goto out; } ret = EXIT_SUCCESS; out: if (config) { ini_config_destroy(config); } return ret; } static int parseBuildRootFile(const char *filePath) { FILE *fp = NULL; unsigned char lineBuf[CONFIG_FILE_LINE_MAXLEN] = {0}; DBG("buildrootFileInfo.fileName is \"%s\" ", filePath); fp = fopen(filePath, "r"); if (!fp) { ERR("error when open buildroot info file"); return EXIT_FAILURE; } while (!feof(fp) && (fgets(lineBuf, CONFIG_FILE_LINE_MAXLEN, fp) != NULL)) { if (NULL != strstr(lineBuf, "#")) { continue; } } fclose(fp); return EXIT_SUCCESS; } static int parseDeviceInfoFile(const char *filePath) { FILE* fp = NULL; int assigns = 0; unsigned int tmp = 0; int hasFwDesc = 0; int hasVendorId = 0; int hasZoneCode = 0; int hasLanguage = 0; int paramInvalid = 0; unsigned char lineBuf[CONFIG_FILE_LINE_MAXLEN] = {0}; unsigned char val[CONFIG_FILE_LINE_MAXLEN] = {0}; unsigned char key[CONFIG_FILE_LINE_MAXLEN] = {0}; fp = fopen(filePath, "r"); if (!fp) { ERR("error when open device info file"); exit(EXIT_FAILURE); } while (!feof(fp) && (fgets(lineBuf, CONFIG_FILE_LINE_MAXLEN, fp) != NULL)) { assigns = sscanf(lineBuf, "%s = %[^\t\r\n]", key, val); if (assigns != 2) { continue; } if (val[0] == '"') /* remove quotes */ { sscanf(val, "\"%[^\"]", val); } if (strcasecmp(key, "FW_DESCRIPTION") == 0) { strncpy(mc.fwDesc, val, sizeof(mc.fwDesc)); hasFwDesc = 1; } else if (strcasecmp(key, "VENDOR_ID") == 0) { sscanf(val, "%x", &tmp); mc.vendorId = (unsigned short)((tmp >> 16) & 0xFFFF); /* use higher 16bit of vendorId */ hasVendorId = 1; } else if (strcasecmp(key, "ZONE_CODE") == 0) { sscanf(val, "%x", &tmp); mc.zoneCode = tmp & 0xFFFF; hasZoneCode = 1; } else if (strcasecmp(key, "LANGUAGE") == 0) { strncpy(mc.language, val, sizeof(mc.language)); /* "CN" or "EN" */ if (strcmp(mc.language, "CN") != 0 && strcmp(mc.language, "EN") != 0) { ERR("language in config file is not correct"); break; } /* turn language to lower case */ mc.language[0] = tolower(mc.language[0]); mc.language[1] = tolower(mc.language[1]); hasLanguage = 1; } else if (strcasecmp(key, "REGION") == 0) { strncpy(mc.region, val, sizeof(mc.region)); /* EU,US etc */ } else if (strcasecmp(key, "IMG_BOOTLOADER_OFFSET") == 0) { sscanf(val, "%x", &mi.bootloaderOffset); } else if (strcasecmp(key, "IMG_BOOTLOADER_LEN") == 0) { sscanf(val, "%x", &mi.bootloaderLen); } else if (strcasecmp(key, "IMG_TAG_OFFSET") == 0) { sscanf(val, "%x", &mi.tagOffset); } else if (strcasecmp(key, "IMG_TAG_LEN") == 0) { sscanf(val, "%x", &mi.tagLen); } else if (strcasecmp(key, "IMG_FACTORY_INFO_LEN") == 0) { sscanf(val, "%x", &mi.factoryInfoLen); } else if (strcasecmp(key, "IMG_UC_OFFSET") == 0) { sscanf(val, "%x", &mi.ucOffset); } else if (strcasecmp(key, "IMG_UC_LEN") == 0) { sscanf(val, "%x", &mi.ucLen); } else if (strcasecmp(key, "IMG_OBJ_DET_MODEL_LEN") == 0) { sscanf(val, "%x", &mi.objdetModelLen); if (mi.objdetModelLen == 0) { gDetModelsInFlash2 = 1; } } else if (strcasecmp(key, "IMG_USR_RECORD_LEN") == 0) { sscanf(val, "%x", &mi.usrRecordLen); } else if (strcasecmp(key, "IMG_KERNEL_OFFSET") == 0) { sscanf(val, "%x", &mi.kernelOffset); } else if (strcasecmp(key, "IMG_KERNEL_LEN") == 0) { sscanf(val, "%x", &mi.kernelLen); } else if (strcasecmp(key, "IMG_ROOTFS_OFFSET") == 0) { sscanf(val, "%x", &mi.rootfsOffset); } else if (strcasecmp(key, "IMG_ROOTFS_LEN") == 0) { sscanf(val, "%x", &mi.rootfsLen); } else if (strcasecmp(key, "IMG_RECOVERY_LEN") == 0) { sscanf(val, "%x", &mi.recoveryLen); } else if (strcasecmp(key, "IMG_SERVICE_OFFSET") == 0) { sscanf(val, "%x", &mi.servicefsOffset); } else if (strcasecmp(key, "IMG_SERVICE_LEN") == 0) { sscanf(val, "%x", &mi.servicefsLen); } else if (strcasecmp(key, "IMG_VERIFY_LEN") == 0) { sscanf(val, "%x", &mi.verifyLen); } else if (strcasecmp(key, "UP_FW_SHARED_PREFIX") == 0) { gUpbootBuildTimes = 0; upPrefix = malloc(strlen(val) + 1); strcpy(upPrefix, val); } else if (strcasecmp(key, "FW_SHARED_PREFIX") == 0) { gUpbootBuildTimes = 0; upPrefix = malloc(strlen(val) + 1); strcpy(upPrefix, val); } #ifdef FLASH_DIAGLOG else if (strcasecmp(key, "IMG_DIAGLOG_LEN") == 0) { sscanf(val, "%x", &mi.diaglogLen); } #endif } fclose(fp); if (!hasFwDesc || !hasVendorId || !hasZoneCode || !hasLanguage || paramInvalid) { ERR("values in device info file are not enough or invalid"); if (upPrefix != NULL) { free(upPrefix); upPrefix = NULL; } return EXIT_FAILURE; } else { return EXIT_SUCCESS; } } static int parseConfigFile() { int ret = EXIT_FAILURE; if (versionFileInfo.fileName == NULL || deviceFileInfo.fileName == NULL || buildTimeInfo.fileName == NULL || fwListFileInfo.fileName == NULL) { ERR("one of the config file not exist"); goto out; } /* first parse version file for version info */ ret = parseVersionFile(versionFileInfo.fileName); if (ret) { goto out; } /* then parse device info file for device info */ ret = parseDeviceInfoFile(deviceFileInfo.fileName); if (ret) { goto out; } /* then parse build root file for device info */ ret = parseBuildRootFile(buildrootFileInfo.fileName); if (ret) { goto out; } /* then stat buildtime file for time info */ ret = parseBuildTimeFile(buildTimeInfo.fileName); if (ret) { goto out; } /* then model files */ if (gFlash2Size || mi.objdetModelLen) { ret = parseModelFiles(); if (ret) { goto out; } } /* finally parse firmware list file for HwID, FL and BL */ ret = parseFwListFile(fwListFileInfo.fileName); if (ret) { goto out; } ret = EXIT_SUCCESS; DBG("parse config file done"); out: return ret; } static int getFileStat(FILE_INFO *fdata) { struct stat st; int res; if (fdata->fileName == NULL) { return -1; } res = stat(fdata->fileName, &st); if (res) { ERRS("stat failed on %s", fdata->fileName); return res; } fdata->fileSize = st.st_size; return 0; } static int checkImageSize(FILE_INFO* fileInfo, int maxSize) { if(getFileStat(fileInfo)) { return -1; } if (fileInfo->fileSize > maxSize) { ERR("image(%s) is too big. expected:%d real:%d", fileInfo->fileName, maxSize, fileInfo->fileSize); return -1; } return 0; } static int initPartitions(void) { int ret = 0; if (0 == mi.bootloaderLen) { DBG("bootloader len is 0"); } if (0 == mi.kernelOffset) { ERR("kernelOffset is not specified"); return -1; } else { DBG("kernel offset is 0x%x(fixed)", mi.kernelOffset); } if (bootloaderInfo.fileName == NULL || ucFileInfo.fileName == NULL || kernelInfo.fileName == NULL || rootfsInfo.fileName == NULL) { ERR("some image is not specified"); return -1; } ret = checkImageSize(&bootloaderInfo, mi.bootloaderLen); if (ret) { return ret; } ret = checkImageSize(&ucFileInfo, mi.ucLen); if (ret) { return ret; } ret = getFileStat(&kernelInfo); if (ret) { return ret; } DBG("kernel file size:0x%x",kernelInfo.fileSize); if (0 != mi.kernelLen) { if (mi.kernelLen < kernelInfo.fileSize) { ERR("fixed kernel length is not enough(beyond 0x%x bytes)", kernelInfo.fileSize - mi.kernelLen); return -1; } } else { mi.kernelLen = kernelInfo.fileSize; mi.kernelLen = ALIGN(mi.kernelLen, 0x10000); } if (gFlash2Size) { if (0 == mi.rootfsLen) { ERR("IMG_ROOTFS_LEN not set"); return -1; } mi.recoveryOffset = mi.kernelOffset + mi.kernelLen; if (gDetModelsInFlash2) { mi.objdetModelOffset = mi.rootfsLen; mi.usrRecordOffset = gFlash2Size * 1024 * 1024 - mi.usrRecordLen; mi.objdetModelLen = mi.usrRecordOffset - mi.objdetModelOffset; mi.servicefsOffset = mi.recoveryOffset + mi.recoveryLen; } else { if (0 == mi.objdetModelLen) { ERR("IMG_OBJ_DET_MODEL_LEN not set"); return -1; } mi.objdetModelOffset = mi.recoveryOffset + mi.recoveryLen; mi.servicefsOffset = mi.objdetModelOffset + mi.objdetModelLen; #ifdef TP_TAPO_TWO_FLASH_USR_RECORD_IN_FLASH2 mi.usrRecord2Len = gFlash2Size * 1024 * 1024 - mi.rootfsLen; #endif } } else { if (0 == mi.rootfsOffset) { mi.rootfsOffset = mi.kernelOffset + mi.kernelLen; DBG("rootfs offset is 0x%x(aligned)", mi.rootfsOffset); } if (mi.rootfsOffset > mi.servicefsOffset) { ERR("kernel is too large, no space left for rootfs"); return -1; } if (0 == mi.objdetModelOffset && mi.objdetModelLen) { mi.objdetModelOffset = mi.servicefsOffset - mi.objdetModelLen; if (0 == mi.recoveryOffset) { mi.recoveryOffset = mi.objdetModelOffset - mi.recoveryLen; } } else { if (0 == mi.recoveryOffset) { mi.recoveryOffset = mi.servicefsOffset - mi.recoveryLen; } } if (0 == mi.rootfsLen) { mi.rootfsLen = mi.recoveryOffset - mi.rootfsOffset; } } if (0 == mi.verifyOffset) { mi.verifyOffset = layout->flashSize - mi.verifyLen; } if (0 == mi.factoryInfoOffset) { mi.factoryInfoOffset = mi.verifyOffset - mi.factoryInfoLen; } if (gDetModelsInFlash2) { if (0 == mi.ucOffset) { mi.ucOffset = mi.factoryInfoOffset - mi.ucLen; } } else { if (0 == mi.usrRecordOffset) { mi.usrRecordOffset = mi.factoryInfoOffset - mi.usrRecordLen; } if (0 == mi.ucOffset) { mi.ucOffset = mi.usrRecordOffset - mi.ucLen; } #ifdef FLASH_DIAGLOG if(0 == mi.diaglogOffset) { mi.diaglogOffset = mi.ucOffset - mi.diaglogLen; } #endif } #ifdef FLASH_DIAGLOG if (0 == mi.servicefsLen) { mi.servicefsLen = mi.diaglogOffset - mi.servicefsOffset; } #else if (0 == mi.servicefsLen) { mi.servicefsLen = mi.ucOffset - mi.servicefsOffset; } #endif ret = getFileStat(&rootfsInfo); if (ret) { return ret; } DBG("rootfs file size:0x%x", rootfsInfo.fileSize); if (rootfsInfo.fileSize > mi.rootfsLen) { ERR("rootfs is too large(beyond 0x%x bytes)", mi.rootfsLen); return -1; } ret = getFileStat(&recoveryFileInfo); if (ret) { return ret; } DBG("recovery file size:0x%x", recoveryFileInfo.fileSize); if (recoveryFileInfo.fileSize > mi.recoveryLen) { ERR("recovery is too large(beyond 0x%x bytes)", mi.recoveryLen); return -1; } ret = getFileStat(&serviceFileInfo); if (ret) { return ret; } DBG("servicefs file size:0x%x", serviceFileInfo.fileSize); if (serviceFileInfo.fileSize > mi.servicefsLen) { ERR("service is too large(beyond 0x%x bytes)", mi.servicefsLen); return -1; } { int i; for (i = 0; i < gDetModelsNum; i++) { ret = getFileStat(&objdetModelFileInfo[i]); if (ret) { return ret; } gDetModelsSizeSum += objdetModelFileInfo[i].fileSize; } gDetModelsSizeSum += sizeof(int) + (sizeof(int) + MODEL_FILE_NAME_SIZE) * gDetModelsNum; DBG("objdet model file size:0x%x", gDetModelsSizeSum); if (gDetModelsSizeSum > mi.objdetModelLen) { ERR("objdet model is too large(beyond 0x%x bytes)", mi.objdetModelLen); return -1; } } if (sizeof(TP_VERIFY) > mi.verifyLen / 2) { ERR("verify struct is too large"); return -1; } DBG("init Partition:"); DBG("[uboot ] is 0x%08x @ 0x%08x | 0x%08x", mi.bootloaderOffset, mi.bootloaderLen, mi.bootloaderLen - bootloaderInfo.fileSize); DBG("[tag ] is 0x%08x @ 0x%08x", mi.tagOffset, mi.tagLen); DBG("[kernel ] is 0x%08x @ 0x%08x | 0x%08x", mi.kernelOffset, mi.kernelLen, mi.kernelLen - kernelInfo.fileSize); DBG("[rootfs ] is 0x%08x @ 0x%08x | 0x%08x", mi.rootfsOffset, mi.rootfsLen, mi.rootfsLen - rootfsInfo.fileSize); if (gDetModelsInFlash2) { DBG("[objdmodel ] is 0x%08x @ 0x%08x | 0x%08x", mi.objdetModelOffset, mi.objdetModelLen, mi.objdetModelLen - gDetModelsSizeSum); DBG("[usr_record ] is 0x%08x @ 0x%08x", mi.usrRecordOffset, mi.usrRecordLen); } DBG("[recover ] is 0x%08x @ 0x%08x | 0x%08x", mi.recoveryOffset, mi.recoveryLen, mi.recoveryLen - recoveryFileInfo.fileSize); if (gFlash2Size && !gDetModelsInFlash2) { DBG("[objdmodel ] is 0x%08x @ 0x%08x | 0x%08x", mi.objdetModelOffset, mi.objdetModelLen, mi.objdetModelLen - gDetModelsSizeSum); } if (0 == gFlash2Size) { DBG("[objdmodel ] is 0x%08x @ 0x%08x | 0x%08x", mi.objdetModelOffset, mi.objdetModelLen, mi.objdetModelLen - gDetModelsSizeSum); } DBG("[servicefs ] is 0x%08x @ 0x%08x | 0x%08x", mi.servicefsOffset, mi.servicefsLen, mi.servicefsLen - serviceFileInfo.fileSize); #ifdef FLASH_DIAGLOG DBG("[diaglog ] is 0x%08x @ 0x%08x", mi.diaglogOffset, mi.diaglogLen); #endif DBG("[config ] is 0x%08x @ 0x%08x | 0x%08x", mi.ucOffset, mi.ucLen, mi.ucLen - ucFileInfo.fileSize); if (!gDetModelsInFlash2) { DBG("[usr_record ] is 0x%08x @ 0x%08x", mi.usrRecordOffset, mi.usrRecordLen); } DBG("[factoryinfo ] is 0x%08x @ 0x%08x", mi.factoryInfoOffset, mi.factoryInfoLen); DBG("[verify ] is 0x%08x @ 0x%08x", mi.verifyOffset, mi.verifyLen); DBG("init Partition done"); return 0; } static int readToBuf(FILE_INFO *fdata, char *buf) { FILE *f; int ret = EXIT_FAILURE; f = fopen(fdata->fileName, "r"); if (f == NULL) { ERRS("could not open \"%s\" for reading", fdata->fileName); goto out; } errno = 0; fread(buf, fdata->fileSize, 1, f); if (errno != 0) { ERRS("unable to read from file \"%s\"", fdata->fileName); goto out_close; } ret = EXIT_SUCCESS; out_close: fclose(f); out: return ret; } static FIRMWARE_INFO *getFwInfo(char* fwType) { FIRMWARE_INFO *firmware; FIRMWARE_INFO *ret = NULL; for (firmware = firmwares; firmware->binType != NULL; firmware++) { if (strcmp(fwType, firmware->binType) == 0) { ret = firmware; break; } } if (NULL == ret) { ERR("firmware bin type \"%s\" not found", fwType); } return ret; } static int getSoftVer(const char* outputPath) { #define LINE_MAX (512) char curConfFileName[LINE_MAX] = {0}; char firstLine[LINE_MAX] = {0}; char *line = curConfFileName; FILE* fp = NULL; int len; int i; snprintf(curConfFileName, LINE_MAX, "%s/%s", outputPath, CURRENT_FW_CONFIG_FILE); /* open info file */ fp = fopen(curConfFileName, "r"); if (NULL == fp) { return EXIT_FAILURE; } /* get version str */ i = 0; while (fgets(line, LINE_MAX, fp)) { if (i == 0) { strcpy(firstLine, line); } if (strstr(line, CONF_FWVER_OPTION)) { if (strstr(line, "=")) { line = strstr(line, "=") + 1; } i = 0; while (line[0] == ' ' && i < LINE_MAX/2) { line++; i++; } strncpy(gSwVer, line, SW_VER_LEN); firstLine[0] = '\0'; break; } i++; } fclose(fp); if (strlen(firstLine)) { strncpy(gSwVer, firstLine, SW_VER_LEN); } len = strlen(gSwVer); for (i = 0; i < len; i++) { if (gSwVer[i] == ' ') { gSwVer[i] = '_'; } } if ('\n' == gSwVer[len - 1]) { gSwVer[len - 1] = 0; } DBG("SwVer:%s", gSwVer); return 0; } static int generateTag(const char* outputPath) { FILE *fp = 0; FILE *fo = 0; struct stat st; char line[CONFIG_FILE_LINE_MAXLEN]; char buf[CONFIG_FILE_LINE_MAXLEN]; char *p; char *q; int n; int ret; /* file with an version str should already exists */ ret = stat(tagInfo.fileName, &st); if (ret || 0 == st.st_size) { DBG("file %s not exist\n", tagInfo.fileName); return EXIT_FAILURE; } fp = fopen(tagInfo.fileName, "r"); if (!strcmp(gSocType, "T23")) { snprintf(buf, CONFIG_FILE_LINE_MAXLEN, "%s/make_tag/tag_generator/build_tag_t23.sh", outputPath); } else if (!strcmp(gSocType, "PRJ007ZL") || !strcmp(gSocType, "PRJ007ZN")) { snprintf(buf, CONFIG_FILE_LINE_MAXLEN, "%s/make_tag/tag_generator/build_tag_PRJ007.sh", outputPath); } else if (!strcmp(gSocType, "PRJ008VL")) { snprintf(buf, CONFIG_FILE_LINE_MAXLEN, "%s/make_tag/tag_generator/build_tag_PRJ008.sh", outputPath); } else { snprintf(buf, CONFIG_FILE_LINE_MAXLEN, "%s/make_tag/tag_generator/build_tag_t41.sh", outputPath); } if (access(buf, F_OK)) { DBG("%s not exist\n", buf); return EXIT_FAILURE; } fo = fopen(buf, "w"); while (fgets(line, CONFIG_FILE_LINE_MAXLEN, fp)) { if (strstr(line, "CMDLINE=")) { char flash_size_str[32]; char flash2_size_str[32]; if (strstr(getLayout(layoutId)->id, "32M")) sprintf(flash_size_str, "32M@0(all)"); else if (strstr(getLayout(layoutId)->id, "16M")) sprintf(flash_size_str, "16M@0(all)"); else if (strstr(getLayout(layoutId)->id, "8M")) sprintf(flash_size_str, "8M@0(all)"); else if (strstr(getLayout(layoutId)->id, "4M")) sprintf(flash_size_str, "4M@0(all)"); sprintf(flash2_size_str, "%dM@0(sall)", gFlash2Size); q = buf; if (!strcmp(gSocType, "T23")) { p = strstr(line, "jz_sfc:"); if (!p) { ERR("jz_sfc not find in tag"); return EXIT_FAILURE; } n = p + strlen("jz_sfc:") - line; } else { p = strstr(line, "sfc0_nor:"); if (!p) { ERR("sfc0_nor not find in tag"); return EXIT_FAILURE; } n = p + strlen("sfc0_nor:") - line; } memcpy(q, line, n); q += n; if (gFlash2Size) { if (gDetModelsInFlash2) { q += sprintf(q, "%dK(boot),%dK(tag),%dK(kernel),%dK(recovery),%dK(system),%dK(config),%dK(factoryinfo),%dK(verify),%s;sfc1_nor:%dK(rootfs),%dK(model),%dK(usrrecord),%s", mi.bootloaderLen/1024, mi.tagLen/1024, mi.kernelLen/1024, mi.recoveryLen/1024, mi.servicefsLen/1024, mi.ucLen/1024, mi.factoryInfoLen/1024, mi.verifyLen/1024, flash_size_str, mi.rootfsLen/1024, mi.objdetModelLen/1024, mi.usrRecordLen/1024, flash2_size_str); } else { #ifdef TP_TAPO_TWO_FLASH_USR_RECORD_IN_FLASH2 q += sprintf(q, "%dK(boot),%dK(tag),%dK(kernel),%dK(recovery),%dK(model),%dK(system),%dK(config),%dK(usrrecord),%dK(factoryinfo),%dK(verify),%s;sfc1_nor:%dK(rootfs),%dK(usrrecord2),%s", mi.bootloaderLen/1024, mi.tagLen/1024, mi.kernelLen/1024, mi.recoveryLen/1024, mi.objdetModelLen/1024, mi.servicefsLen/1024, mi.ucLen/1024, mi.usrRecordLen/1024, mi.factoryInfoLen/1024, mi.verifyLen/1024, flash_size_str, mi.rootfsLen/1024, mi.usrRecord2Len/1024, flash2_size_str); #else q += sprintf(q, "%dK(boot),%dK(tag),%dK(kernel),%dK(recovery),%dK(model),%dK(system),%dK(config),%dK(usrrecord),%dK(factoryinfo),%dK(verify),%s;sfc1_nor:%dK(rootfs),%s", mi.bootloaderLen/1024, mi.tagLen/1024, mi.kernelLen/1024, mi.recoveryLen/1024, mi.objdetModelLen/1024, mi.servicefsLen/1024, mi.ucLen/1024, mi.usrRecordLen/1024, mi.factoryInfoLen/1024, mi.verifyLen/1024, flash_size_str, mi.rootfsLen/1024, flash2_size_str); #endif } p = strstr(line, flash2_size_str); if (!p) { ERR("%s not find in tag", flash2_size_str); return EXIT_FAILURE; } n = strlen(line) - (p + strlen(flash2_size_str) - line); memcpy(q, p + strlen(flash2_size_str), n); strncpy(line, buf, CONFIG_FILE_LINE_MAXLEN); } else { if (mi.objdetModelLen) { #ifdef FLASH_DIAGLOG q += sprintf(q, "%dK(boot),%dK(tag),%dK(kernel),%dK(rootfs),%dK(recovery),%dK(model),%dK(system),%dK(diaglog),%dK(config),%dK(usrrecord),%dK(factoryinfo),%dK(verify),%s", mi.bootloaderLen/1024, mi.tagLen/1024, mi.kernelLen/1024, mi.rootfsLen/1024, mi.recoveryLen/1024, mi.objdetModelLen/1024, mi.servicefsLen/1024, mi.diaglogLen/1024, mi.ucLen/1024, mi.usrRecordLen/1024, mi.factoryInfoLen/1024, mi.verifyLen/1024, flash_size_str); #else q += sprintf(q, "%dK(boot),%dK(tag),%dK(kernel),%dK(rootfs),%dK(recovery),%dK(model),%dK(system),%dK(config),%dK(usrrecord),%dK(factoryinfo),%dK(verify),%s", mi.bootloaderLen/1024, mi.tagLen/1024, mi.kernelLen/1024, mi.rootfsLen/1024, mi.recoveryLen/1024, mi.objdetModelLen/1024, mi.servicefsLen/1024, mi.ucLen/1024, mi.usrRecordLen/1024, mi.factoryInfoLen/1024, mi.verifyLen/1024, flash_size_str); #endif } else { q += sprintf(q, "%dK(boot),%dK(tag),%dK(kernel),%dK(rootfs),%dK(recovery),%dK(system),%dK(config),%dK(usrrecord),%dK(factoryinfo),%dK(verify),%s", mi.bootloaderLen/1024, mi.tagLen/1024, mi.kernelLen/1024, mi.rootfsLen/1024, mi.recoveryLen/1024, mi.servicefsLen/1024, mi.ucLen/1024, mi.usrRecordLen/1024, mi.factoryInfoLen/1024, mi.verifyLen/1024, flash_size_str); } p = strstr(line, flash_size_str); if (!p) { ERR("%s not find in tag", flash_size_str); return EXIT_FAILURE; } n = strlen(line) - (p + strlen(flash_size_str) - line); memcpy(q, p + strlen(flash_size_str), n); strncpy(line, buf, CONFIG_FILE_LINE_MAXLEN); } } else if (strstr(line, "BOOTINFO=")) { if (!strcmp(gSocType, "T23")) { /* kernel=5M@0x98000 rootfs=3M@0x598000 */ sprintf(line, "BOOTINFO=\"kernel=%dK@0x%x rootfs=%dK@0x%x\"\n", mi.kernelLen/1024, mi.kernelOffset, mi.rootfsLen/1024, mi.rootfsOffset); } else { /* SFC0:kernel=3M@0x80000 rootfs=3M@0x380000 */ if (gFlash2Size) { sprintf(line, "BOOTINFO=\"SFC0:kernel=%dK@0x%x; SFC1:rootfs=%dK@0x00000\"\n", mi.kernelLen/1024, mi.kernelOffset, mi.rootfsLen/1024, mi.rootfsOffset); } else { sprintf(line, "BOOTINFO=\"SFC0:kernel=%dK@0x%x rootfs=%dK@0x%x\"\n", mi.kernelLen/1024, mi.kernelOffset, mi.rootfsLen/1024, mi.rootfsOffset); } } } fwrite(line, strlen(line), 1, fo); } fclose(fp); fclose(fo); snprintf(buf, CONFIG_FILE_LINE_MAXLEN, "%s/make_tag/build_camera_tag.sh %s %s", outputPath, outputPath, outputPath); system(buf); sprintf(tagInfo.fileName, "%s/tag.bin", outputPath); if (gStagingHostDir && serviceFileInfo.fileName) { /* tag_up.bin */ char cmd[512]; system("[ -d squashfs-root ] && rm -rf squashfs-root"); sprintf(cmd, "%s/bin/unsquashfs4 %s", gStagingHostDir, serviceFileInfo.fileName); system(cmd); if (!strcmp(gSocType, "T23")) { sprintf(cmd, "dd if=%s of=tag_up.bin bs=1024 skip=64 count=288; mv tag_up.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); if (gTagUpAddUserinfo) { sprintf(cmd, "dd if=%s of=user_info bs=1024 skip=20 count=4; cat squashfs-root/etc/tag_up.bin user_info > tag_up.bin; mv tag_up.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); } sprintf(cmd, "dd if=%s of=tag_sensor.bin bs=1024 skip=4 count=4; mv tag_sensor.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); sprintf(cmd, "dd if=%s of=tag_ae_table_up.bin bs=1024 skip=24 count=4; mv tag_ae_table_up.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); } else if (!strcmp(gSocType, "PRJ007ZL") || !strcmp(gSocType, "PRJ007ZN")) { sprintf(cmd, "dd if=%s of=tag_up.bin bs=1024 skip=64 count=400; mv tag_up.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); sprintf(cmd, "dd if=%s of=tag_sensor.bin bs=1024 skip=4 count=4; mv tag_sensor.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); } else { sprintf(cmd, "dd if=%s of=tag_head_up.bin bs=1 skip=0 count=54; mv tag_head_up.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); sprintf(cmd, "dd if=%s of=tag_up.bin bs=1024 skip=64 count=192; mv tag_up.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); sprintf(cmd, "dd if=%s of=tag_sensor.bin bs=1024 skip=4 count=4; mv tag_sensor.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); sprintf(cmd, "dd if=%s of=tag_ae_table_up.bin bs=1024 skip=16 count=4; mv tag_ae_table_up.bin squashfs-root/etc/", tagInfo.fileName); system(cmd); } if (gSquashfsBlocksize) { sprintf(cmd, "%s/bin/mksquashfs4 squashfs-root %s -nopad -noappend -root-owned -comp xz -b %dk -processors 1", gStagingHostDir, serviceFileInfo.fileName, gSquashfsBlocksize); } else { sprintf(cmd, "%s/bin/mksquashfs4 squashfs-root %s -nopad -noappend -root-owned -comp lzo", gStagingHostDir, serviceFileInfo.fileName); } DBG("%s", cmd); system(cmd); system("rm -rf squashfs-root"); ret = getFileStat(&serviceFileInfo); if (ret) { return ret; } DBG("servicefs file size:0x%x", serviceFileInfo.fileSize); if (serviceFileInfo.fileSize > mi.servicefsLen) { ERR("service is too large(beyond 0x%x bytes)", mi.servicefsLen); return -1; } } return 0; } static int setFirmwareName(const char* format, char* fwName, const char* outputPath) { char* tmpName = NULL; char* prefixName = prefix; if (NULL != upPrefix) { prefixName = upPrefix; } if (NULL == prefixName) { ERR("firmware prefix name not specified"); return -1; } snprintf(fwName, FIRMWARE_NAME_MAXLEN, format, prefixName, mc.language, gSwVer); if (NULL != outputPath) /* if output path is specified, add path before name */ { tmpName = strdup(fwName); if (NULL == tmpName) { return -1; } snprintf(fwName, FIRMWARE_NAME_MAXLEN, "%s/%s", outputPath, tmpName); free(tmpName); } return 0; } static void getMd5(char *data, int size, char *md5) { MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, data, size); MD5_Final(md5, &ctx); } static void getMd5_two(char *data, int size, char *data2, int size2, char *md5) { MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, data, size); MD5_Update(&ctx, data2, size2); MD5_Final(md5, &ctx); } static void fillVerify(char* contentBase, int len, int upDataOffset, int serviceLenAligned, int detModelLenAligned) { TP_VERIFY* hdr = (TP_VERIFY*)(contentBase + mi.bootloaderLen); TP_VERIFY* hdr_backup = (TP_VERIFY*)(contentBase + mi.bootloaderLen + upDataOffset / 2); int i = 0; memset(hdr, 0, upDataOffset); hdr->headerVersion = htonl(TP_HEADER_VERSION); memcpy(hdr->magicNumber, tpVerifyMagicNumber, MAGIC_LEN); hdr->kernelLoadAddress = htonl(mi.kernelOffset); hdr->kernelEntryPoint = htonl(mi.kernelOffset); hdr->vendorId = htons(mc.vendorId); hdr->zoneCode = htons(mc.zoneCode); hdr->partitionNum = htonl(PARTITION_NUMBER); hdr->factoryBootOffset = 0; hdr->factoryBootLen = 0; hdr->factoryInfoOffset = htonl(mi.factoryInfoOffset); hdr->factoryInfoLen = htonl(mi.factoryInfoLen); hdr->radioOffset= 0; hdr->radioLen = 0; hdr->ucOffset = htonl(mi.ucOffset); hdr->ucLen = htonl(mi.ucLen); hdr->bootloaderOffset= htonl(mi.bootloaderOffset); hdr->bootloaderLen = htonl(mi.bootloaderLen); hdr->tpHeaderOffset = htonl(mi.verifyOffset); hdr->tpHeaderLen = htonl(mi.verifyLen); hdr->kernelOffset= htonl(mi.kernelOffset); hdr->kernelLen = htonl(mi.kernelLen); hdr->romFsOffset = htonl(mi.rootfsOffset); hdr->romFsLen = htonl(mi.rootfsLen); hdr->jffs2FsOffset = htonl(mi.servicefsOffset); hdr->jffs2FsLen = htonl(mi.servicefsLen); hdr->jffs2RealFsLen = htonl(serviceLenAligned); hdr->modelFsOffset = htonl(mi.objdetModelOffset); hdr->modelFsLen = htonl(mi.objdetModelLen); /* calc md5 for bootloaderCRC */ getMd5(contentBase + mi.bootloaderOffset, mi.bootloaderLen, hdr->ubootCRC); /* cal md5 for kernelAndRomfsCRC */ if (gFlash2Size) { getMd5_two(contentBase + upDataOffset + mi.kernelOffset, mi.kernelLen + mi.recoveryLen, contentBase + upDataOffset + mi.rootfsOffset, mi.rootfsLen, hdr->kernelAndRomfsCRC); } else { getMd5(contentBase + upDataOffset + mi.kernelOffset, mi.kernelLen + mi.rootfsLen + mi.recoveryLen, hdr->kernelAndRomfsCRC); } /* cal md5 for serviceCRC */ if (gFlash2Size) { if (gDetModelsInFlash2) { getMd5_two(contentBase + upDataOffset + mi.rootfsOffset + mi.rootfsLen, detModelLenAligned, contentBase + upDataOffset + mi.servicefsOffset, serviceLenAligned, hdr->serviceCRC); } else { getMd5(contentBase + upDataOffset + mi.objdetModelOffset, mi.objdetModelLen + serviceLenAligned, hdr->serviceCRC); } } else { getMd5(contentBase + upDataOffset + mi.objdetModelOffset, mi.objdetModelLen + serviceLenAligned, hdr->serviceCRC); } hdr->isVerified = 0; /* fill Fw Description */ memcpy(hdr->fwDescription, mc.fwDesc, FW_DESC_LEN); /* fill Sw Ver */ memcpy(hdr->swVer, gSwVer, SWVER_LEN); memcpy(hdr->swVerMagicNum, swVersionMagicNumber, MAGIC_LEN); DBG("swVer \"%s\" ", hdr->swVer); /* cal md5 to fill FwID at last */ getMd5(contentBase + upDataOffset, len, hdr->fwId); memcpy(fwID, hdr->fwId, FW_ID_LEN); memcpy(hdr_backup, hdr, sizeof(TP_VERIFY)); } static void checkOnVerify(char* contentBase, int upDataOffset) { TP_VERIFY* hdr = (TP_VERIFY*)(contentBase + mi.bootloaderLen); TP_VERIFY* hdr_backup = (TP_VERIFY*)(contentBase + mi.bootloaderLen + upDataOffset / 2); hdr->isVerified = 1; memcpy(hdr_backup, hdr, sizeof(TP_VERIFY)); } static int fillFactoryInfo(char* buf, const char *devName) { unsigned int fac_data_len = 0; FACTORY_INFO* facInfo = (FACTORY_INFO*)buf; char tmp[128] = {0}; char *name = NULL; char *ver = NULL; char *content_buf = NULL; int content_len = 0; char hw_id_str[128] = {0}; char oem_id_str[128] = {0}; char *format = NULL; if (devName != NULL) { memcpy(tmp, devName, strlen(devName)); name = tmp; while (*name != '_' && *name != '\0') name++; if (*name == '_') *name = '\0'; ver = name+1; name = tmp; } if (hex2str(hwIdListArr[0], HW_ID_LEN, hw_id_str, sizeof(hw_id_str))) { return -1; } if (hex2str(oemIdArr[0], OEM_ID_LEN, oem_id_str, sizeof(oem_id_str))) { return -1; } content_buf = malloc(mi.factoryInfoLen); if (content_buf == NULL) { return -1; } memset(content_buf, 0, sizeof(content_buf)); DBG("hw_id: %s", hw_id_str); DBG("oem_id: %s", oem_id_str); if (getFileStat(&factoryInfo)) { /* 若机型配置中不存在factoryinfo.config,则使用默认的factory_info内容填充factory_info分区 */ snprintf(content_buf, mi.factoryInfoLen, gDefaultFactoryInfoFmt, hw_id_str, name?name:"", ver?ver:"", oem_id_str, mc.region); /* 包含\0 */ content_len = strlen(content_buf) + 1; memcpy(buf + sizeof(FACTORY_INFO), content_buf, content_len); } else { format = malloc(factoryInfo.fileSize + 1); if (format == NULL) { free(content_buf); return -1; } memset(format, 0 ,factoryInfo.fileSize + 1); /* 若机型配置中存在factoryinfo.config,则直接使用factoryinfo.config的内容填充factory_info分区 */ if (readToBuf(&factoryInfo, format)) { free(format); free(content_buf); return -1; } snprintf(content_buf, mi.factoryInfoLen, format, hw_id_str, name?name:"", ver?ver:"", oem_id_str, mc.region); content_len = strlen(content_buf) + 1; memcpy(buf + sizeof(FACTORY_INFO), content_buf, content_len); free(format); } memset(facInfo, 0, sizeof(FACTORY_INFO)); memcpy(facInfo->magicNumber, fInfoMagicNumber, 4); memcpy(&facInfo->version, fInfoVersion, 2); fInfoDataLength = htons(content_len); memcpy(&facInfo->dataLength, (unsigned char*)&fInfoDataLength, 2); getMd5(buf + sizeof(FACTORY_INFO), content_len, buf + sizeof(FACTORY_INFO) + content_len); free(content_buf); return content_len + sizeof(FACTORY_INFO) + FINFO_MD5_LEN; } static int writeToBinFile(char* buf, int len, char* ofName) { int ret = EXIT_FAILURE; FILE *f; /* open firmware file and write */ f = fopen(ofName, "w"); if (NULL == f) { ERRS("could not open \"%s\" for writing", ofName); goto out; } errno = 0; fwrite(buf, len, 1, f); if (errno) { ERRS("unable to write output file"); goto out_flush; } DBG("firmware file \"%s\" completed", ofName); ret = EXIT_SUCCESS; out_flush: fflush(f); fclose(f); if (ret != EXIT_SUCCESS) { unlink(ofName); } out: return ret; } static void fillUpgradeHeader_RSA2048(char* buf, int len, unsigned short contentTypes) { UPGRADE_HEADER_RSA2048* hdr = (UPGRADE_HEADER_RSA2048*)buf; unsigned char *hwIDList = (unsigned char*)hdr->hwIdList; unsigned char *fwIDFList = NULL; unsigned char *oemIDist = NULL; int i = 0; int quotient = 0; int reminder = 0; memset(buf, 0, uhTagLength); hdr->headerVersion = htonl(UPGRADE_HEADER_VERSION_2048); memcpy(hdr->magicNumber, upgradeHeaderMagicNumber, MAGIC_LEN); hdr->tagLength = htons(uhTagLength); hdr->vendorId = htons(mc.vendorId); hdr->zoneCode = htons(mc.zoneCode); hdr->contentTypes = htons(contentTypes); hdr->hwIdNum = htons((unsigned short)hwIdNum); hdr->fwIdFLNum = htons((unsigned short)fwIdFLNum); hdr->oemIdNum = htons((unsigned short)oemIdNum); /* cal FL mask, default mask support every FwID in the list */ quotient = fwIdFLNum / 8; reminder = fwIdFLNum % 8; if (quotient != 0) { memset(hdr->fwIdFLMask, 0xff, quotient); } if (reminder != 0) { memset(&(hdr->fwIdFLMask)[quotient], 0xff << (8 - reminder), 1); } /* fill support HwIDs and FL and oemIDs */ for(i = 0; i < hwIdNum; i++) { memcpy((hwIDList + i * HW_ID_LEN), hwIdListArr[i], HW_ID_LEN); } fwIDFList = hwIDList + hwIdNum * HW_ID_LEN; for(i = 0; i < fwIdFLNum; i++) { memcpy((fwIDFList + i * FW_ID_LEN), fwIdFLArr[i], FW_ID_LEN); } oemIDist = hwIDList + hwIdNum * HW_ID_LEN + fwIdFLNum * FW_ID_LEN; for(i = 0; i < oemIdNum; i++) { memcpy((oemIDist + i * OEM_ID_LEN), oemIdArr[i], OEM_ID_LEN); } } static int writeFw(char *fwBase, int fwLen, const char* outputPath, char *fwType, int bFillUH) { int ret = EXIT_FAILURE; FIRMWARE_INFO *fwInfo; char outputFwName[FIRMWARE_NAME_MAXLEN] = {0}; /* get firmware info by firmware ID */ fwInfo = getFwInfo(fwType); if (NULL == fwInfo) { goto out; } /* fill upgrade header if needed */ if (bFillUH) { fillUpgradeHeader_RSA2048(fwBase, fwLen, fwInfo->contentParts); } ret = setFirmwareName(fwInfo->formatName, outputFwName, outputPath); if (ret) { goto out; } ret = writeToBinFile(fwBase, fwLen, outputFwName); if (ret) { goto out; } ret = EXIT_SUCCESS; out: return ret; } static char *getFileBasename(char *file_str) { char *p = file_str; char *p2 = p; while (p = strchr(p,'/')) { p++; p2 = p; } p = p2; while (p = strchr(p,'\\')) { p++; p2 = p; } return p2; } static int fillDetModel(char* fwBase, char * p) { int i; int *pp; pp = p; *pp = gDetModelsNum; pp++; for (i = 0; i < gDetModelsNum; i++) { *pp = objdetModelFileInfo[i].fileSize; pp++; } DBG("read objmodel to 0x%x", p - fwBase); p = pp; for (i = 0; i < gDetModelsNum; i++) { strcpy(p, getFileBasename(objdetModelFileInfo[i].fileName)); p += MODEL_FILE_NAME_SIZE; } for (i = 0; i < gDetModelsNum; i++) { int ret = readToBuf(&objdetModelFileInfo[i], p); p += objdetModelFileInfo[i].fileSize; if (ret) { return 1; } } return 0; } /* up.bin [uboot ] [verify ] [tag ] [kernel ] [rootfs ] [recovery ] [detmodel ] [servicefs ] real file size flash.bin [uboot ] [tag ] [kernel ] [rootfs ] [recovery ] [detmodel ] [servicefs ] [config ] [usr_record ] [factoryinfo ] [verify ] */ static int buildFw(const char* outputPath, const char *devName) { int i = 0; char *buf = NULL; char *p = NULL; char *fwBase = NULL; int fwLen = 0; int facinfo_len = 0; int ret = EXIT_FAILURE; int upDataOffset = mi.verifyLen; int bufLen = layout->flashSize + uhTagLength + upDataOffset; int serviceLenAligned = ALIGN(serviceFileInfo.fileSize, 0x10000); int detModelLenAligned = ALIGN(gDetModelsSizeSum, 0x10000); if (gFlash2Size) { bufLen += mi.rootfsLen; if (gDetModelsInFlash2) { bufLen += mi.objdetModelLen; } } buf = (char *)malloc(bufLen); if (!buf) { ERR("no memory for buffer"); goto out_free_buf; } memset(buf, 0xff, bufLen); fwBase = buf + uhTagLength; /* have a up header before bootloader */ p = fwBase + mi.bootloaderOffset; DBG("read bootloader to 0x%x",p - fwBase); ret = readToBuf(&bootloaderInfo, p); if (ret) { goto out_free_buf; } ret = getFileStat(&tagInfo); if (ret) { goto out_free_buf; } p = fwBase + upDataOffset + mi.tagOffset; DBG("read tag to 0x%x",p - fwBase); ret = readToBuf(&tagInfo, p); if (ret) { goto out_free_buf; } p = fwBase + upDataOffset + mi.kernelOffset; DBG("read kernel to 0x%x", p - fwBase); ret = readToBuf(&kernelInfo, p); if (ret) { goto out_free_buf; } if (0 == gFlash2Size) { p = fwBase + upDataOffset + mi.rootfsOffset; DBG("read rootfs to 0x%x", p - fwBase); ret = readToBuf(&rootfsInfo, p); if (ret) { goto out_free_buf; } } p = fwBase + upDataOffset + mi.recoveryOffset; DBG("read recovery to 0x%x", p - fwBase); ret = readToBuf(&recoveryFileInfo, p); if (ret) { goto out_free_buf; } if (gFlash2Size && !gDetModelsInFlash2) { p = fwBase + upDataOffset + mi.objdetModelOffset; if (fillDetModel(fwBase, p)) { goto out_free_buf; } } else if (0 == gFlash2Size) { p = fwBase + upDataOffset + mi.objdetModelOffset; if (fillDetModel(fwBase, p)) { goto out_free_buf; } } p = fwBase + upDataOffset + mi.servicefsOffset; DBG("read system to 0x%x", p - fwBase); ret = readToBuf(&serviceFileInfo, p); if (ret) { goto out_free_buf; } p += serviceLenAligned; if (gFlash2Size) { DBG("two: read rootfs to 0x%x, 0x%x", p - fwBase, mi.rootfsLen); mi.rootfsOffset = p - fwBase - upDataOffset; ret = readToBuf(&rootfsInfo, p); if (ret) { goto out_free_buf; } p += mi.rootfsLen; if (gDetModelsInFlash2) { char *pb = p; if (fillDetModel(fwBase, p)) { goto out_free_buf; } p = pb + detModelLenAligned; } } fillVerify(fwBase, p - fwBase - upDataOffset, upDataOffset, serviceLenAligned, detModelLenAligned); if (gUpbootBuildTimes != 1) { fwLen = p - buf; ret = writeFw(buf, fwLen, outputPath, "up_boot.bin", 1); if (ret != EXIT_SUCCESS) { goto out_free_buf; } if(gUpbootBuildTimes == 0) { gUpbootBuildTimes = 1; } } if (gFlash2Size) { if (gDetModelsInFlash2) { memset(fwBase + upDataOffset + mi.servicefsOffset + serviceLenAligned, 0xFF, mi.rootfsLen + mi.objdetModelLen); } else { memset(fwBase + upDataOffset + mi.servicefsOffset + serviceLenAligned, 0xFF, mi.rootfsLen); } } checkOnVerify(fwBase, upDataOffset); memcpy(fwBase + upDataOffset + mi.verifyOffset, fwBase + mi.bootloaderLen, mi.verifyLen); for (i = mi.bootloaderLen / upDataOffset - 1; i >= 0; i--) { memcpy(fwBase + upDataOffset * (i + 1), fwBase + upDataOffset * i, upDataOffset); } fwLen = layout->flashSize; /* fill uc partition with uc file */ p = fwBase + upDataOffset + mi.ucOffset; ret = readToBuf(&ucFileInfo, p); if (ret) { goto out_free_buf; } p = fwBase + upDataOffset + mi.factoryInfoOffset; facinfo_len = fillFactoryInfo(p, devName); if (facinfo_len == -1) { goto out_free_buf; } ret = writeFw(fwBase + upDataOffset, fwLen, outputPath, "flash.bin", 0); if (ret != EXIT_SUCCESS) { goto out_free_buf; } if (gFlash2Size) { memset(fwBase, 0xff, gFlash2Size * 1024 * 1024); ret = readToBuf(&rootfsInfo, fwBase); if (ret) { goto out_free_buf; } p = fwBase + mi.rootfsLen; if (gDetModelsInFlash2 && fillDetModel(fwBase, p)) { goto out_free_buf; } ret = writeFw(fwBase, gFlash2Size * 1024 * 1024, outputPath, "flash2.bin", 0); } DBG("make firmware done"); ret = EXIT_SUCCESS; out_free_buf: if (buf) { free(buf); } out: return ret; } static void usage(int status) { FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; fprintf(stream, "Usage: %s [OPTIONS...]\n", progName); fprintf(stream, "\n" "Options:\n" " -E <ep> overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n" " -L <la> overwrite kernel load address with <la> (hexval prefixed with 0x)\n" " -F <id> use flash layout specified with <id>\n" " -k <file> read kernel image from the file <file>\n" " -r <file> read rootfs image from the file <file>\n" " -b <file> read bootloader image from the file <file>\n" " -f <file> read factory bootloader image from the file <file>\n" " -p <prefix> the prefix of the firmware file name.\n" " -R <rev> the revision of the firmware.\n" " -s <size> the size of the upgrade header, default is 512\n" " -a <align> align the rootfs start on an <align> bytes boundary\n" " -i <file> inspect given firmware file <file>\n" " -v <file> specify firmware version config file <file>\n" " -B <file> specify firmware buildroot file <file>\n" " -d <file> specify firmware device info config file <file>\n" " -t <file> specify firmware build time file <file>\n" " -u <file> specify firmware user config file for flash.bin<file>\n" " -o <path> specify firmware output path <path>, local dir if not specified\n" " -c <path> specify product_config path <path>\n" " -A use signature protocol RSA2048, default is RSA1024\n" " -h show this screen\n"); exit(status); } static int writeInfo(char* outputPath) { char fileName[512] = {0}; FILE* fp = NULL; INI_CONFIG* config = NULL; int ret = EXIT_FAILURE; unsigned char idStr[2*FW_ID_LEN + 1] = {0}; unsigned char verStr[GENERATED_VERSION_STR_MAXLEN] = {0}; struct stat sbuf; snprintf(fileName, 512, "%s/%s", outputPath, CURRENT_FW_CONFIG_FILE); /* file with an version str should already exists */ ret = stat(fileName, &sbuf); if (ret || 0 == sbuf.st_size) { DBG("file %s not exist\n", fileName); return EXIT_FAILURE; } /* open info file */ fp = fopen(fileName, "r"); if (NULL == fp) { DBG("open %s failed\n", fileName); return EXIT_FAILURE; } /* get version str */ fgets(verStr, GENERATED_VERSION_STR_MAXLEN, fp); if (strncmp(verStr+1, CONF_CURRENT_FW_SECTION, 5) == 0) { fclose(fp); DBG("get version str failed\n"); return 0; } fclose(fp); /* make firwmare id str */ ret = hex2str(fwID, FW_ID_LEN, idStr, sizeof(idStr)); if (ret) { DBG("hex2str error\n"); return EXIT_FAILURE; } /* reopen file with write mode */ fp = fopen(fileName, "w"); if (NULL == fp) { DBG("open %s failed\n", fileName); return EXIT_FAILURE; } /* write section "current firmware" */ fprintf(fp, "[%s]\n", CONF_CURRENT_FW_SECTION); fprintf(fp, "%s = %s\n", CONF_FWID_OPTION, idStr); fprintf(fp, "%s = %s", CONF_FWVER_OPTION, verStr); fprintf(fp, "%s = %s\n", CONF_SVNVER_OPTION, revStr); fprintf(fp, "%s = \n", CONF_RELNOTE_OPTION); fprintf(fp, "%s = \n", CONF_INFL_OPTION); fprintf(fp, "%s = \n", CONF_INBL_OPTION); /* write section "generated list" */ fprintf(fp, "\n"); fprintf(fp, "[%s]\n", CONF_GENLIST_SECTION); fprintf(fp, "%s = %s\n", CONF_CURFW_FL_OPTION, fwIdFLIndexStr); fprintf(fp, "%s = %s\n", CONF_CURFW_BL_OPTION, fwIdBLIndexStr); fprintf(fp, "%s = %s\n", CONF_CURFW_HWID_LIST_OPTION, hwIdListIndexStr); fprintf(fp, "%s = %s\n", CONF_CURFW_OEMID_LIST_OPTION, oemIdIndexStr); fclose(fp); DBG("%s generated", CURRENT_FW_CONFIG_FILE); return EXIT_SUCCESS; } int main(int argc, char *argv[]) { int ret = EXIT_FAILURE; int c = 0; int i = 0; int err = 0; FILE *outfile = NULL; char* outputPath = NULL; char DevNameList[1024] = {0}; char *ptr = NULL; progName = basename(argv[0]); while (1) { c = getopt(argc, argv, "F:I:H:O:b:T:k:r:m:A:C:v:d:l:B:t:u:p:R:o:D:S:U"); if (c == -1) break; switch (c) { case 'F': layoutId = optarg; break; case 'I': factoryInfo.fileName = optarg; break; case 'H': gStagingHostDir = optarg; break; case 'O': gSquashfsBlocksize = atoi(optarg); break; case 'b': bootloaderInfo.fileName = optarg; break; case 'T': tagInfo.fileName = optarg; break; case 'k': kernelInfo.fileName = optarg; break; case 'r': rootfsInfo.fileName = optarg; break; case 'C': recoveryFileInfo.fileName = optarg; break; case 'm': serviceFileInfo.fileName = optarg; break; case 'A': gDetModelsDir = optarg; break; case 'v': versionFileInfo.fileName = optarg; break; case 'd': deviceFileInfo.fileName = optarg; break; case 'l': fwListFileInfo.fileName = optarg; break; case 'B': buildrootFileInfo.fileName = optarg; break; case 't': buildTimeInfo.fileName = optarg; break; case 'u': ucFileInfo.fileName = optarg; break; case 'p': prefix = optarg; break; case 'R': revStr = optarg; break; case 'o': outputPath = optarg; break; case 'D': gFlash2Size = atoi(optarg); break; case 'S': gSocType = optarg; break; case 'U': gTagUpAddUserinfo = 1; break; default: usage(EXIT_FAILURE); break; } } ret = checkOptions(); if (ret) { goto out; } ret = parseConfigFile(); if (ret) { goto out; } ret = initPartitions(); if (ret) { goto out; } getSoftVer(outputPath); ret = generateTag(outputPath); if (ret) { goto out; } ret = buildFw(outputPath, NULL); if (ret) { goto out; } ret = writeInfo(outputPath); if (ret) { goto out; } out: if (upPrefix != NULL) { free(upPrefix); upPrefix = NULL; } return ret; }

罗依琳
  • 粉丝: 0
上传资源 快速赚钱