色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

ARM SCP入門-framework框架代碼分析

yzcdx ? 來源:OS與AUTOSAR研究 ? 2023-07-03 09:32 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

一套軟硬件跑起來的樣子就像上面圖里面的一樣,it works。對應我們的SCP固件中,有那些框架來支撐這個系統運行起來,這里就需要一套基于M核或者單片機的通用框架程序,市面上的這種系統并不少見,例如freeRTOS等。

為了強調安全、簡單等特性,適配ARM控制系統固件,ARM又搞了這套通用的框架,適合在M核或者R核上工作,甚至A核的某些特權系統例如OPTEE中。安全的核心就是隔離,隔離就是按功能形成module或者domain,模塊之間禁止無權限的訪問

1. module介紹

SCP的每個功能都實現為一個單獨的module,module間耦合盡量低,確保安全特性,通常固件所需的整體功能應來自模塊之間的交互。module間隔離就像上圖中的狗咬架,一旦伸手產生交互就禍福不能預測了,所以加上欄桿規定好那些module間可以交互伸手,這都是通過API函數實現的,在系統初始化的時候設定死,下面模塊間綁定章節會講到。

SCP中的module分為兩部分:在代碼根目錄module文件夾下,共77個公共模塊,另外每個產品下面還有module,小100個可真不少。

240b4608-192e-11ee-962d-dac502259ad0.png

一個固件只包含一部分module,在Firmware.cmake中定義,gen_module_code.py腳本生成源碼

這些module在framework啟動時候初始化啟動運行。

公共的module比較有通用性,產品自己的module一般是驅動需要進行定制

模塊類型及軟件協議棧:

2445db74-192e-11ee-962d-dac502259ad0.png

這個協議棧就是SCP軟件跟外界交互的流程,一般消息都是通過驅動-》HAL層上來,然后處理的過程就是服務-》協議-》HAL-》驅動再操作硬件做出反應,這次交互就算結束了。具體如下:

2475854a-192e-11ee-962d-dac502259ad0.png

2.framework框架流程

2492c20e-192e-11ee-962d-dac502259ad0.png

framework框架負責固件的通用流程實現,包括系統初始化,module初始化,中斷服務提供,event服務提供等。這樣module就可以專注于自己功能和對外交互api的實現。SCP framework初始化流程圖如下:

251ddaa6-192e-11ee-962d-dac502259ad0.png

備注:這里的framework框架流程適用于scp_romfwscp_ramfw,兩者區別只是包含module不同,定義包含了那些module在其目錄下的Firmware.cmake文件中。

編譯過程中gen_module_code.py腳本會生成module信息和配置信息的代碼,過程如下:SCP/MCP 軟件構建系統由一個頂級 Makefile :Makefile.cmake和一組 .mk 文件組成,例如juno產品product/juno/product.mk

BS_PRODUCT_NAME := juno

BS_FIRMWARE_LIST := scp_romfw
scp_romfw_bypass
scp_ramfw

模塊可以在項目根目錄的 modules/ 目錄下實現,也可以是產品特定的并在product//modules 目錄下實現。

gen_module_code.py腳本會根據

product/juno/scp_romfw/Firmware.cmake中SCP_MODULES變量

list(APPEND SCP_MODULES "juno-ppu")
list(APPEND SCP_MODULES "juno-rom")
list(APPEND SCP_MODULES "juno-soc-clock")
list(APPEND SCP_MODULES "clock")
list(APPEND SCP_MODULES "gtimer")
list(APPEND SCP_MODULES "sds")
list(APPEND SCP_MODULES "bootloader")

生成

?fwk_module_idx.h:包含構成固件的模塊索引的枚舉。fwk_module_idx.h中枚舉中模塊索引的順序保證遵循固件firmware.mk 文件中 BS_FIRMWARE_MODULES列表中模塊名稱的順序。當執行涉及迭代固件中存在的所有模塊的操作時,框架在運行時使用相同的順序,例如 fwk_module.c 中的 init_modules() 函數。

enum fwk_module_idx {
FWK_MODULE_IDX_JUNO_PPU = 0,
FWK_MODULE_IDX_JUNO_ROM = 1,
FWK_MODULE_IDX_JUNO_SOC_CLOCK = 2,
FWK_MODULE_IDX_CLOCK = 3,
FWK_MODULE_IDX_GTIMER = 4,
FWK_MODULE_IDX_SDS = 5,
FWK_MODULE_IDX_BOOTLOADER = 6,
FWK_MODULE_IDX_COUNT = 7,
};

?fwk_module_list.c:包含一個指向模塊描述符的指針表,每個模塊對應一個作為固件一部分構建的模塊。該文件及其內容由框架內部使用,通常不應由其他單元(如模塊)使用。

const struct fwk_module *module_table[FWK_MODULE_IDX_COUNT] = {
&module_juno_ppu,
&module_juno_rom,
&module_juno_soc_clock,
&module_clock,
&module_gtimer,
&module_sds,
&module_bootloader,

};
const struct fwk_module_config *module_config_table[FWK_MODULE_IDX_COUNT] = {
&config_juno_ppu,
&config_juno_rom,
&config_juno_soc_clock,
&config_clock,
&config_gtimer,
&config_sds,
&config_bootloader,
};

module_tablemodule_config_table用于模塊初始化。

固件的Firmware.cmake文件中可以對配置開關進行聲明,例如:

set(SCP_FIRMWARE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}")

set(SCP_GENERATE_FLAT_BINARY TRUE)
set(SCP_ARCHITECTURE "arm-m")

framework.md-固件相關配置文件說明

產品始終包含定義一個或多個固件目標的product.mk文件。

在一個產品中,總會有至少一個固件。

對于每個固件,必須在fmw_memory.h文件中提供鏈接器信息,例如product/juno/scp_romfw/fmw_memory.h中:

#define FMW_MEM_MODE ARCH_MEM_MODE_DUAL_REGION_RELOCATION

/* ROM */
#define FMW_MEM0_SIZE SCP_ROM_SIZE
#define FMW_MEM0_BASE SCP_ROM_BASE

/* RAM */
#define FMW_MEM1_SIZE (16 * 1024)
#define FMW_MEM1_BASE (SCP_RAM_BASE + SCP_RAM_SIZE - FMW_MEM1_SIZE)

如果使用雙區域內存配置,則還必須定義FMW_MEM1_BASE和 FMW_MEM1_SIZE 。

Toolchain-*.cmake 中定義image的體系結構目標

product/juno/scp_romfw/Toolchain-GNU.cmake

set(CMAKE_SYSTEM_PROCESSOR "cortex-m3")
set(CMAKE_TOOLCHAIN_PREFIX "arm-none-eabi-")
...

product/juno/scp_romfw/CMakeLists.txt 定義編譯范圍和目標,cmake會使用生成makefile文件。

編譯選項說明:

cmake_readme.md-構建配置選項:

?SCP_ENABLE_NOTIFICATIONS:啟用/禁用 SCP 固件中的通知。

?SCP_ENABLE_SCMI_NOTIFICATIONS:啟用/禁用 SCMI 通知。

?SCP_ENABLE_RESOURCE_PERMISSIONS:啟用/禁用資源權限設置。

單獨配置編譯:

配置生效命令:

cmake -B /tmp/build -DSCP_FIRMWARE_SOURCE_DIR:PATH=juno/scp_romfw -DSCP_ENABLE_DEBUG_UNIT=TRUE

然后就是編譯命令:

cmake --build /tmp/build

在編譯文件中配置,例如在product/juno/scp_romfw/Firmware.cmake中

set(SCP_ENABLE_NOTIFICATIONS TRUE)

修改后需要clean下,再繼續編譯。

2.1 平臺初始化

arch/arm/arm-m/CMakeLists.txt中,arch-arm-m庫的入口是arch_exception_reset()函數:

if(CMAKE_C_COMPILER_ID  STREQUAL "ARMClang")     target_link_options(arch-arm-mPUBLIC  "LINKER:--entry=arch_exception_reset")endif()

arch_exception_reset()函數在arch/arm/arm-m/src/arch.ld.S鏈接文件中也被定位了入口函數

其實現在arch/arm/arm-m/src/arch_handlers.c:

 noreturn  void arch_exception_reset(void) {     
 extern noreturn void __main(void);     
 __main(); 
 }

__main在c運行時調用main函數,對于M核實現來說,arch/arm/arm-m/src/arch_main.c中有main()函數

int main(void)
{
////初始化 ARM Cortex-M 系列芯片的 Configuration Control Register (CCR)。
//其中,通過設置 SCB_CCR_DIV_0_TRP_Msk 來啟用除以零的異常處理
arch_init_ccr();

//scp 入口及應用函數
return fwk_arch_init(&arch_init_driver);
}

scp 入口及應用為fwk_arch_init函數,在framework/src/fwk_arch.c中

int fwk_arch_init(const struct fwk_arch_init_driver *driver)
{
//scp 框架初始化,完成module_table、module_config_table所有模塊信息的初始化
//scp/module目錄下的模塊的初始化
fwk_module_init();

//這里構建了一個全局的fwk_io_stdin、 fwk_io_stdout, 在后面的終端輸出有用
status = fwk_io_init();

//初始化日志輸出方式
status = fwk_log_init();

//中斷gic初始化
status = fwk_arch_interrupt_init(driver->interrupt);

//所有模塊初始化,開始任務
status = fwk_module_start();

//循環等待處理隊列事件
__fwk_run_main_loop();
}

2.2 module初始化

fwk_module_init函數,在framework/src/fwk_module.c中實現

在系統構建章節中module_table和module_config_table是由配置文件Firmware.cmake生成的fwk_module_list.c中定義。

module見module介紹章節

module_config_table就是模塊的上下文信息

void fwk_module_init(void)
{
for (uint32_t i = 0U; i < ?(uint32_t)FWK_MODULE_IDX_COUNT; i++) {
//獲取模塊的上下文信息
struct fwk_module_context *ctx = &fwk_module_ctx.module_ctx_table[i];

fwk_id_t id = FWK_ID_MODULE(i);
const struct fwk_module *desc = module_table[i];
const struct fwk_module_config *config = module_config_table[i];

//給模塊上下文信息賦值
*ctx = (struct fwk_module_context){
.id = id,
.desc = desc,
.config = config,
};

//初始化模塊的鏈表
fwk_list_init(&ctx->delayed_response_list);

if (config->elements.type == FWK_MODULE_ELEMENTS_TYPE_STATIC) {
size_t notification_count = 0;

#ifdef BUILD_HAS_NOTIFICATION
notification_count = desc->notification_count;
#endif

fwk_module_init_element_ctxs(
ctx, config->elements.table, notification_count);
}

#ifdef BUILD_HAS_NOTIFICATION
if (desc->notification_count > 0) {
fwk_module_init_subscriptions(
&ctx->subscription_dlist_table, desc->notification_count);
}
#endif
}
}

2.3 中斷初始化

static int fwk_arch_interrupt_init(int (*interrupt_init_handler)(
const struct fwk_arch_interrupt_driver **driver))
{
const struct fwk_arch_interrupt_driver *driver;

status = interrupt_init_handler(&driver);

/* Initialize the interrupt management component */
status = fwk_interrupt_init(driver);

return FWK_SUCCESS;
}

interrupt_init_handler是入參回調函數,對應為arch_init_driver

static const struct fwk_arch_init_driver arch_init_driver = {
.interrupt = arch_nvic_init,
};

在arch_nvic_init中有*driver =&arch_nvic_driver;

static const struct fwk_arch_interrupt_driver arch_nvic_driver = {
.global_enable = global_enable,
.global_disable = global_disable,
.is_enabled = is_enabled,
.enable = enable,
.disable = disable,
.is_pending = is_pending,
.set_pending = set_pending,
.clear_pending = clear_pending,
.set_isr_irq = set_isr_irq,
.set_isr_irq_param = set_isr_irq_param,
.set_isr_nmi = set_isr_nmi,
.set_isr_nmi_param = set_isr_nmi_param,
.set_isr_fault = set_isr_fault,
.get_current = get_current,
.is_interrupt_context = is_interrupt_context,
};

拿到driver的值后,執行fwk_interrupt_init(driver);

int fwk_interrupt_init(const struct fwk_arch_interrupt_driver *driver)
{
//校驗driver
fwk_interrupt_driver = driver;
initialized = true;

return FWK_SUCCESS;
}

fwk_interrupt_driver 全局變量用于中斷處理。

模塊使用中斷時,需要調用對外接口在framework/include/fwk_interrupt.h中,

例如開啟中斷fwk_interrupt_enable函數的實現:

int fwk_interrupt_enable(unsigned int interrupt)
{
if (!initialized) {
return FWK_E_INIT;
}

return fwk_interrupt_driver->enable(interrupt);
}

2.4 module啟動

fwk_module_start()在framework/src/fwk_module.c中定義

int fwk_module_start(void)
{
//初始化任務列表
status = __fwk_init(FWK_MODULE_EVENT_COUNT);
fwk_module_ctx.stage = MODULE_STAGE_INITIALIZE;

//從功能方面初始化所有module
fwk_module_init_modules();
fwk_module_ctx.stage = MODULE_STAGE_BIND;

//調用模塊.bind回調函數完成所有模塊的綁定。(此處共進行兩輪調用fwk_module_bind_module(round=0 1),
//每輪都將分別綁定模塊module和模塊的元素element)
for (bind_round = 0; bind_round <= FWK_MODULE_BIND_ROUND_MAX;
bind_round++) {
status = fwk_module_bind_modules(bind_round);
if (status != FWK_SUCCESS) {
return status;
}
}
fwk_module_ctx.stage = MODULE_STAGE_START;

//啟動模塊
status = start_modules();
fwk_module_ctx.initialized = true;

return FWK_SUCCESS;
}

fwk_module_init_modules函數調用fwk_module_init_module對每個模塊進行功能初始化

//初始化模塊元素上下文(element_ctxs),
//調用模塊的config->elements.generator,獲取element信息,加入模塊上下文表
elements = config->elements.generator(ctx->id);
fwk_module_init_element_ctxs(ctx, elements, notification_count);

//調用模塊的init函數,傳入element_count,config->dat
status = desc->init(ctx->id, ctx->element_count, config->data);

//初始化模塊元素(element),調用模塊回調函數.element_init將模塊element->data配置信息導入到模塊內部
fwk_module_init_elements(ctx);

start_modules函數調用fwk_module_start_module對每個模塊進行啟動

module = fwk_mod_ctx->desc;

//調用模塊.start回調函數
module->start(fwk_mod_ctx->id);

例如在juno_rom的.start回調函數函數中,通過event和notification機制,到達juno_rom模塊的相應回調函數,在juno_rom中,通過ctx.bootloader_api->load_image()調用mod_bootloader的api,從安全內存拷貝到指定位置,在該bootloader模塊api中加載跳轉scp_ramfw。(注mod_bootloader_boot為匯編實現,依賴arm指令)。在product/juno/module/juno_rom/src/mod_juno_rom.c中:

const struct fwk_module module_juno_rom = {
.type = FWK_MODULE_TYPE_SERVICE,
.event_count = (unsigned int)MOD_JUNO_ROM_EVENT_COUNT,
.notification_count = (unsigned int)MOD_JUNO_ROM_NOTIFICATION_COUNT,
.init = juno_rom_init,
.bind = juno_rom_bind,
.start = juno_rom_start,
.process_event = juno_rom_process_event,
.process_notification = juno_rom_process_notification,
};

2.5 運行狀態機

scp-firmware在完成了所有的初始化操作后,進入死循環,處理隊列里面的事件或者休眠等待事件到來。

noreturn void __fwk_run_main_loop(void)
{
for (;;) {
fwk_process_event_queue();
if (fwk_log_unbuffer() == FWK_SUCCESS) {
fwk_arch_suspend();
}
}
}

fwk_process_event_queue主要處理三個重要的鏈表:free_event_queue, event_queue, isr_event_queue所有的操作都是圍繞這三個隊列展開。

void fwk_process_event_queue(void)
{
for (;;) {
while (!fwk_list_is_empty(&ctx.event_queue)) {
process_next_event();
}

if (!process_isr()) {
break;
}
}
}

event_queue中根據target_id找到對應module,然后調用module->process_event進行處理,詳細見module中說明。

process_next_event中調用duplicate_event會處理free_event_queue隊列中的事件

process_isr從中斷isr_event_queue隊列中取到事件,然后加入到event_queue中

3.module對外接口

在scp代碼中,所有的功能都由一個個模塊提供。每個模塊以api枚舉及其結構體的方式對外提供該模塊的功能,并在模塊通用結構體fwk_module中提供,例如

module/scmi_power_domain/src/mod_scmi_power_domain.c中,

/* SCMI Power Domain Management Protocol Definition */
const struct fwk_module module_scmi_power_domain = {
.api_count = 1,
.type = FWK_MODULE_TYPE_PROTOCOL,
.init = scmi_pd_init,
.bind = scmi_pd_bind,
.start = scmi_pd_start,
.process_bind_request = scmi_pd_process_bind_request,
.event_count = (unsigned int)SCMI_PD_EVENT_IDX_COUNT,
.process_event = scmi_pd_process_event,
#ifdef BUILD_HAS_MOD_DEBUG
.process_notification = scmi_pd_process_notification,
#endif
};

.init(模塊初始化)

.bind(獲取綁定別的模塊的api)

.process_bind_request(被其他模塊依賴的api的獲取并綁定請求函數)等通用接口。

.start模塊啟動

.process_event事件處理

.process_notification通知處理

初始化模塊:

模塊在初始化時由fwk_module.c 中fwk_module_start函數,調用回調函數.init,.bind,.start

?模塊初始化:調用模塊API的init()函數指針

?元素初始化:調用框架模塊API的element_init()函數指針

?后初始化:元素初始化后,模塊交互之前的一些可選處理操作

?綁定:模塊必須綁定好才能調用對方的api

?開始

運行時:

一旦運行前階段成功完成,固件將開始處理模塊或中斷引發的事件。默認情況下,固件將永遠循環等待新事件在運行前階段結束時處理,但當事件列表為空時,可以在處理未決事件后返回。

模塊配置:

模塊初始化的時候,模塊配置被讀入存放到模塊上下文中:

const struct fwk_module_config *config = module_config_table[i];

//給模塊上下文信息賦值
*ctx = (struct fwk_module_context){
.id = id,
.desc = desc,
.config = config,
};

在module_config_table在fwk_module_list.c中定義,這里以config_juno_ppu為例:

const struct fwk_module_config *module_config_table[FWK_MODULE_IDX_COUNT] = {
&config_juno_ppu,

struct fwk_module_config config_juno_ppu = {
.data =
&(struct mod_juno_ppu_config){
.timer_alarm_id = FWK_ID_SUB_ELEMENT_INIT(
FWK_MODULE_IDX_TIMER,
0,
JUNO_PPU_ALARM_IDX),
},

.elements = FWK_MODULE_DYNAMIC_ELEMENTS(get_element_table),
};

#define FWK_MODULE_DYNAMIC_ELEMENTS(GENERATOR)
{
.type = FWK_MODULE_ELEMENTS_TYPE_DYNAMIC,
.generator = (GENERATOR),
}

如果類型為FWK_MODULE_ELEMENTS_TYPE_STATIC ,框架使用表指針中給出的靜態表來訪問產品為模塊提供的元素表。

如果類型為 FWK_MODULE_ELEMENTS_TYPE_DYNAMIC ,則框架使用生成器函數指針。

get_element_table對應一個配置結構體數組:

static struct fwk_element element_table[] = {
[JUNO_PPU_DEV_IDX_BIG_SSTOP] = {
.name = "",
.data = &(const struct mod_juno_ppu_element_config) {
.reg_base = PPU_BIG_SSTOP_BASE,
.timer_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_TIMER, 0),
.pd_type = MOD_PD_TYPE_CLUSTER,
},
},
....

enum juno_ppu_idx {
JUNO_PPU_DEV_IDX_BIG_CPU0,
JUNO_PPU_DEV_IDX_BIG_CPU1,
JUNO_PPU_DEV_IDX_BIG_SSTOP,

JUNO_PPU_DEV_IDX_LITTLE_CPU0,
JUNO_PPU_DEV_IDX_LITTLE_CPU1,
JUNO_PPU_DEV_IDX_LITTLE_CPU2,
JUNO_PPU_DEV_IDX_LITTLE_CPU3,
JUNO_PPU_DEV_IDX_LITTLE_SSTOP,

JUNO_PPU_DEV_IDX_GPUTOP,
JUNO_PPU_DEV_IDX_SYSTOP,
JUNO_PPU_DEV_IDX_DBGSYS,

JUNO_PPU_DEV_IDX_COUNT,
};

struct fwk_element結構體表示元素,里面有名字,子元素個數和數據

元素:

元素表示由模塊擁有或管理的資源。每個元素將表示模塊與之交互和/或負責的對象。

例如,驅動程序類型的模塊可能具有表示它所控制的硬件設備的元素。因為元素配置數據靈活多變,使用通用的方式const void *data實現。

子元素表示由元素擁有或管理的資源。子元素僅由它們的索引和/或標識符表示。

索引和標識符:

由于框架設計為模塊化,因此需要一種標準化方法來識別和引用模塊、元素、子元素、事件、通知和 API。該框架為此定義了兩個組件:indices和identifiers。

indices:

模塊索引由構建系統為每個固件生成,并放在fwk_module_idx.h頭文件中。

enum fwk_module_idx {
FWK_MODULE_IDX_JUNO_PPU = 0,
FWK_MODULE_IDX_JUNO_ROM = 1,
......

identifiers:

標識符有一個類型,這決定了標識符中包含的信息。在內部,標識符始終包含模塊的索引,并且可能包含在該模塊的上下文中標識項目的附加索引。也在fwk_module_idx.h頭文件中,有宏和變量兩部分定義,值是一樣的:

#define FWK_MODULE_ID_JUNO_PPU FWK_ID_MODULE(FWK_MODULE_IDX_JUNO_PPU)
#define FWK_ID_MODULE(MODULE_IDX) ((fwk_id_t)FWK_ID_MODULE_INIT(MODULE_IDX))
#define FWK_ID_MODULE_INIT(MODULE_IDX)
{
.common = {
.type = (uint32_t)__FWK_ID_TYPE_MODULE,
.module_idx = (uint32_t)MODULE_IDX,
},
}

static const fwk_id_t fwk_module_id_juno_ppu = FWK_MODULE_ID_JUNO_PPU_INIT;
#define FWK_MODULE_ID_JUNO_PPU_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_JUNO_PPU)

可用的標識符類型有:

?模塊:僅由模塊索引組成

?元素:由模塊索引和模塊內元素的索引組成

?子元素:由模塊索引、模塊內元素的索引和該元素擁有的子元素的索引組成。

?API:由模塊索引和模塊提供的API的索引組成

?事件:由模塊索引和模塊可能產生的事件的索引組成

?通知:由模塊索引和模塊可能生成的通知索引組成。

日志:

日志記錄功能定義并實現了該組件的公共接口。該接口的文檔可以在 fwk_log.h 中找到。

#include
FWK_LOG_ERR("[ROM] ERROR: Failed to turn on LITTLE cluster.");
# define FWK_LOG_ERR(...) fwk_log_printf(__VA_ARGS__)

fwk_log_printf()函數在framework/src/fwk_log.c中定義。

4. event事件

255e9582-192e-11ee-962d-dac502259ad0.png

模塊可以給自己或者別的模塊發送event事件,事件的參數是結構化消息structfwk_event

static int juno_rom_process_event(
const struct fwk_event *event,
struct fwk_event *resp)
{

truct fwk_event {
struct fwk_slist_node slist_node;
fwk_id_t source_id;
fwk_id_t target_id;
uint32_t cookie;
bool is_response;
bool response_requested;
bool is_notification;
bool is_delayed_response;
fwk_id_t id;
alignas(max_align_t) uint8_t params[FWK_EVENT_PARAMETERS_SIZE];
};

該事件包含一個response_requested 屬性,該屬性指示源實體是否期望對其事件的響應。為了響應這個事件,接收實體填寫響應參數,框架發出一個事件,該事件以發出原始事件的實體為目標。

事件的is_response屬性用于指示新生成的事件是對原始事件的響應。

例如在juno_rom固件初始化時,初始化juno_rom模塊,product/juno/module/juno_rom/src/mod_juno_rom.c

會執行.start回調函數函數juno_rom_start(),給自己發了一個event,如下:

static int juno_rom_start(fwk_id_t id)
{
struct fwk_event event = {
.source_id = fwk_module_id_juno_rom,
.target_id = fwk_module_id_juno_rom,
.id = mod_juno_rom_event_id_run,
};
.....
return fwk_put_event(&event);
}

#define fwk_put_event(event)
_Generic((event), struct fwk_event *
: __fwk_put_event, struct fwk_event_light *
: __fwk_put_event_light)(event)

fwk_put_event把event分為兩類,fwk_event_light 是輕量級的攜帶不攜帶額外數據參數。這里我們用fwk_event 則處理函數為:

__fwk_put_event
--》put_event(event,
intr_state, FWK_EVENT_TYPE_STD);
--》fwk_list_push_tail(&ctx.event_queue,
&allocated_event->slist_node);

固件狀態機運行的時候會循環執行framework/src/fwk_core.c中process_next_event()函數

static void process_next_event(void)
{
ctx.current_event = event = FWK_LIST_GET(
fwk_list_pop_head(&ctx.event_queue), struct fwk_event, slist_node);

module = fwk_module_get_ctx(event->target_id)->desc;
process_event = event->is_notification ? module->process_notification :
module->process_event;

status = process_event(event, &async_response_event);

這里找到模塊juno_rom,然后取出其event處理函數process_event并執行,實際執行的是juno_rom_process_event(),其發了一條通知消息如下:

static int juno_rom_process_event(
const struct fwk_event *event,
struct fwk_event *resp)
{
....
/* Send SYSTOP ON notification */
systop_on_event =
(struct fwk_event){ .response_requested = true,
.id = mod_juno_rom_notification_id_systop,
.source_id = FWK_ID_NONE };

notification_params = (void *)systop_on_event.params;
notification_params->state = (unsigned int)MOD_PD_STATE_ON;

//發notification消息
status = fwk_notification_notify(&systop_on_event, &ctx.notification_count);
if (!fwk_expect(status == FWK_SUCCESS)) {
return FWK_E_PANIC;
}

//通過ctx.bootloader_api->load_image()調用mod_bootloader的api,從安全內存拷貝到指定位置,
//在該bootloader 模塊api中加載跳轉scp_ramfw。
if (ctx.notification_count == 0) {
return deferred_setup();
}

fwk_notification_notify的解釋見notification章節

5.motificaiont通知

notification涉及到兩個模塊的通信,跟event的區別是:

?event是一個模塊發給另外一個模塊或者發給自己,比較確定

?notification是發給訂閱了這個模塊的所有模塊,算廣播,需要先進行訂閱

notification接口:

?fwk_notification_subscribe//訂閱指定模塊指定通知

?fwk_notification_unsubscribe//取消訂閱通知

?fwk_notification_notify//向訂閱該通知的模塊發送通知

在實現上notification使用event的消息傳遞機制,只在發消息和處理消息的時候做微小改動。

例如上面例子中使用fwk_notification_notify()函數發送的通知

int fwk_notification_notify(struct fwk_event *notification_event,unsigned int *count){
send_notifications(notification_event, count);

通知的參數沿用event的struct fwk_event ,發送通知的時候,需要先找到訂閱鏈表,然后進行過濾

static void send_notifications(struct fwk_event *notification_event,
unsigned int *count)
{
//根據id和source_id找到訂閱的鏈表
subscription_dlist = get_subscription_dlist(notification_event->id,
notification_event->source_id);
notification_event->is_response = false;
notification_event->is_notification = true;

for (node = fwk_list_head(subscription_dlist); node != NULL;
node = fwk_list_next(subscription_dlist, node)) {
subscription = FWK_LIST_GET(node,
struct __fwk_notification_subscription, dlist_node);

//對比源id如果相同就進行發送
if (!fwk_id_is_equal(
subscription->source_id, notification_event->source_id)) {
continue;
}

notification_event->target_id = subscription->target_id;

status = __fwk_put_notification(notification_event);
if (status == FWK_SUCCESS) {
(*count)++;
}
}
}

get_subscription_dlist函數中source_id 決定是模塊上下文還是元素上下文

.id = mod_juno_rom_notification_id_systop,
.source_id = FWK_ID_NONE };

static const fwk_id_t mod_juno_rom_notification_id_systop =
FWK_ID_NOTIFICATION_INIT(
FWK_MODULE_IDX_JUNO_ROM,
MOD_JUNO_ROM_NOTIFICATION_IDX_SYSTOP);

拿到subscription_dlist訂閱列表后,就進行過濾發送通知

int __fwk_put_notification(struct fwk_event *event)
{
event->is_response = false;
event->is_notification = true;

return put_event(event, UNKNOWN_STATE, FWK_EVENT_TYPE_STD);
}

這里就使用了event進行實現。然后系統狀態機在處理event的時候,

static void process_next_event(void)
{
ctx.current_event = event = FWK_LIST_GET(
fwk_list_pop_head(&ctx.event_queue), struct fwk_event, slist_node);

module = fwk_module_get_ctx(event->target_id)->desc;
process_event = event->is_notification ? module->process_notification :
module->process_event;

根據is_notification 就可以知道是notification 了,然后調用process_notification 進行處理

6.模塊綁定

一個模塊或元素可以綁定到另一個模塊或模塊內的元素。目標是相同的 - 獲取指向可在后續階段使用的 API 的指針。當嘗試綁定到模塊內的元素(而不是模塊本身)時,主要區別在于接收和處理綁定請求的模塊能夠根據目標元素更改其行為。例如,可以允許請求綁定的模塊僅綁定到處理請求的模塊內的元素子集。

思路:A模塊要與B模塊通信,A模塊的全局變量要拿到B模塊的回調函數

A模塊在初始化的時候,會調用自己的bind函數,

bind--》fwk_module_bind--》B模塊的process_bind_request()函數,從而拿到api

25fd5cda-192e-11ee-962d-dac502259ad0.png

scmi_power_domain模塊調用scmi模塊的api函數示例圖

scmi_pd_ctx.scmi_api賦值為scmi模塊的處理函數,在.bind = scmi_pd_bind中,

static int scmi_pd_bind(fwk_id_t id, unsigned int round)
{
status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_PROTOCOL),
&scmi_pd_ctx.scmi_api);

fwk_module_bind調用依賴模塊提供的process_bind_request函數來獲取依賴模塊的api,并綁定。

int fwk_module_bind(fwk_id_t target_id, fwk_id_t api_id, const void *api)
{
fwk_mod_ctx = fwk_module_get_ctx(target_id);

status = fwk_mod_ctx->desc->process_bind_request(
fwk_module_ctx.bind_id, target_id, api_id, (const void **)api);

target_id是FWK_MODULE_IDX_SCMI,對應SCMI模塊,fwk_mod_ctx 是SCMI模塊的上下文

/* SCMI module definition */
const struct fwk_module module_scmi = {
.api_count = (unsigned int)MOD_SCMI_API_IDX_COUNT,
.event_count = 1,
#ifdef BUILD_HAS_NOTIFICATION
.notification_count = (unsigned int)MOD_SCMI_NOTIFICATION_IDX_COUNT,
#endif
.type = FWK_MODULE_TYPE_SERVICE,
.init = scmi_init,
.element_init = scmi_service_init,
.bind = scmi_bind,
.start = scmi_start,
.process_bind_request = scmi_process_bind_request,
.process_event = scmi_process_event,
#ifdef BUILD_HAS_NOTIFICATION
.process_notification = scmi_process_notification,
#endif
};

scmi_process_bind_request調用到

static int scmi_process_bind_request(fwk_id_t source_id, fwk_id_t target_id,
fwk_id_t api_id, const void **api)
{
unsigned int api_idx;
struct scmi_service_ctx *ctx;
enum mod_scmi_api_idx api_id_type;

api_idx = fwk_id_get_api_idx(api_id);

api_id_type = (enum mod_scmi_api_idx)api_idx;

switch (api_id_type) {
case MOD_SCMI_API_IDX_PROTOCOL:
if (!fwk_id_is_type(target_id, FWK_ID_TYPE_MODULE)) {
return FWK_E_SUPPORT;
}

if (scmi_ctx.protocol_count >= scmi_ctx.config->protocol_count_max) {
return FWK_E_NOMEM;
}

scmi_ctx.protocol_table[PROTOCOL_TABLE_RESERVED_ENTRIES_COUNT +
scmi_ctx.protocol_count++].id = source_id;
*api = &scmi_from_protocol_api;
break;

到此scmi_power_domain模塊拿到了scmi模塊的處理函數,放入&scmi_pd_ctx.scmi_api

幾個關鍵的模塊間api調用示例:

mod_scmi_power_domain模塊中scmi消息收發:

?scmi模塊綁定各個scmi協議模塊的protocol_api,根據id來找到此模塊api,執行該protocol;

?scmi_power_domain模塊綁定scmi模塊的api,通過調用scmi_api(mod_scmi.c中)來回復該protocol;

mod_scmi.c/transport_api調用mod_smt中的transport相關功能來完成scmi協議的transport層(scmi 數據收發及解析);

mod_smt.c/driver_api調用scmi更下一級的channel來產生中斷(scmi消息通知中斷產生和處理)。





審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • ARM處理器
    +關注

    關注

    6

    文章

    361

    瀏覽量

    42724
  • 耦合器
    +關注

    關注

    8

    文章

    735

    瀏覽量

    61598
  • FreeRTOS
    +關注

    關注

    13

    文章

    495

    瀏覽量

    64696
  • 狀態機
    +關注

    關注

    2

    文章

    494

    瀏覽量

    28359
  • MCP
    MCP
    +關注

    關注

    0

    文章

    274

    瀏覽量

    14483

原文標題:ARM SCP入門-framework框架代碼分析

文章出處:【微信號:OS與AUTOSAR研究,微信公眾號:OS與AUTOSAR研究】歡迎添加關注!文章轉載請注明出處。

收藏 0人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    ARM SCP入門-簡介和代碼下載編譯

    在現代SoC芯片中CPU只能說是皇帝,掌握資源命脈的還得是太上皇 SCP
    發表于 07-02 10:33 ?8049次閱讀
    <b class='flag-5'>ARM</b> <b class='flag-5'>SCP</b><b class='flag-5'>入門</b>-簡介和<b class='flag-5'>代碼</b>下載編譯

    嵌入式框架Zorb Framework搭建方案

    Zorb Framework是一個基于面向對象的思想來搭建一個輕量級的嵌入式框架
    的頭像 發表于 11-05 17:08 ?2042次閱讀
    嵌入式<b class='flag-5'>框架</b>Zorb <b class='flag-5'>Framework</b>搭建方案

    嵌入式框架Zorb Framework狀態機的實現

    Zorb Framework是一個基于面向對象的思想來搭建一個輕量級的嵌入式框架
    的頭像 發表于 11-29 09:33 ?2145次閱讀
    嵌入式<b class='flag-5'>框架</b>Zorb <b class='flag-5'>Framework</b>狀態機的實現

    ARM入門基礎好書

    `ARM入門基礎好書本文從學習者的角度出發,分別描述了下面幾部分內容:ARM編程的基本知識,BOOT代碼流程和功能分析,OS中斷程序的編寫舉
    發表于 10-31 16:52

    .NET Micro Framework簡介

    的方式實現了源代碼完全開放。  1.哪些領域可以采用.NET Micro Framework技術?  .NET Micro Framework技術可以應用到:Sideshow、遠程控制、智能家電
    發表于 05-27 16:03

    .Net Micro Framework 快速入門

    ?  .NET Micro Framework對存儲器和處理器的要求更低。開發人員可以在低功耗、低成本的ARM7、ARM9、Blackfin和Cortex-M3處理器上使用該框架(不需
    發表于 05-29 10:56

    [資料分享]+Android框架揭秘

    框架入門教材使用。 三、看看目錄,了解其主要內容 《android框架揭秘》第1章 android framework概要 11.1 android源代碼組成 21.2 通過啟動過程
    發表于 09-26 09:47

    Labview Actor Framework 框架使用例子(反饋式蒸發器)

    工作中遇到老外的項目,用的是Actor Framework框架,所以最近這段時間學習了下。但網上這塊資料非常少,就算是有也是非常簡單的介紹。后面看到這篇博客http://blog.csdn.net
    發表于 11-17 19:36

    Android Framework電源子系統的分析

    系列文章解讀&說明:Android Framework 電源子系統 的分析主要分為以下部分:Android Framework 電源子系統(01)PowerManagerService啟動
    發表于 12-31 06:51

    CH372DLL.dll在.NET Framework 4.7.2及以上版本框架會閃退如何解決?

    問題:CH372DLL.dll 在 .NET Framework 3.5 及以下版本框架工作正常,.NET Framework 4.7.2 及以上版本框架會閃退請問如何解決
    發表于 07-19 06:18

    ARM入門 Study ARM Step by Step

    ARM入門 Study ARM Step by Step本文從學習者的角度出發,分別描述了下面幾個部分內容:ARM編程的基本知識,BOOT代碼
    發表于 02-10 10:57 ?193次下載

    ARM處理器的啟動代碼分析與設計

    ARM處理器的啟動代碼分析與設計
    發表于 09-25 08:27 ?12次下載
    <b class='flag-5'>ARM</b>處理器的啟動<b class='flag-5'>代碼</b>的<b class='flag-5'>分析</b>與設計

    關于嵌入式應用框架(EAF)的分析

    EAF是Embedded Application Framework 的縮寫,即嵌入式應用框架。嵌入式應用框架是 Application framework的一種, 是在嵌入式領域的應
    發表于 01-01 09:50 ?1807次閱讀

    ARM SCP入門-AP與SCP通信

    當Linux想要關機或者休眠的時候,這涉及到整個系統電源狀態的變化,為了安全性Linux內核沒有權利去直接執行了,需要陷入到EL3等級去執行,可以參考之前文章ARM ATF入門-安全固件軟件介紹和代碼運行
    的頭像 發表于 07-16 11:25 ?6904次閱讀
    <b class='flag-5'>ARM</b> <b class='flag-5'>SCP</b><b class='flag-5'>入門</b>-AP與<b class='flag-5'>SCP</b>通信

    framework框架流程 模塊綁定

    framework框架負責固件的通用流程實現,包括系統初始化,module初始化,中斷服務提供,event服務提供等。這樣module就可以專注于自己功能和對外交互api的實現。SCP
    的頭像 發表于 11-02 17:24 ?1094次閱讀
    <b class='flag-5'>framework</b><b class='flag-5'>框架</b>流程 模塊綁定
    主站蜘蛛池模板: 五月激情丁香婷婷 | 国产亚洲tv在线观看 | 欧美日韩在线观看视频 | 国产欧美一区二区三区国产幕精品 | 国产男女猛烈无遮挡免费视频网站 | 国产a级一级片 | 337p粉嫩大胆色噜噜噜 | 野外偷拍做爰全过程 | 国产又大又黑又粗 | 久久久www成人免费毛片女 | 天天插夜夜爽 | 亚洲二区在线播放视频 | bb日韩美女预防毛片视频 | 综合激情亚洲 | 麻豆蜜桃av蜜臀av色欲av | 国产日产欧美一区二区 | 特黄大片又粗又大又暴 | 亚洲影视综合网 | 影音先锋在线中文字幕 | 啪啪小视频网站 | 久久精品在线 | 337p日本欧洲亚洲大胆艺术图 | 北条麻妃在线一区二区 | 亚洲成人黄 | 天天爱天天做天天爽夜夜揉 | 国产日产亚洲精品 | 免费看日批视频 | 五十路熟女一区二区三区 | 天堂va蜜桃 | 麻豆国产97在线 | 欧美 | 色噜噜av | 毛片永久新网址首页 | jizz亚洲女人 | 一级成人av| 成人精品自拍 | 91精品啪 | 日韩一区二区三区福利视频 | 欧美中文字幕 | 国产精品毛片久久久久久久 | 欧美日韩一区二区三区不卡视频 | 欧美国产日韩在线 | 日日碰狠狠添天天爽五月婷 | 欧洲人妻丰满av无码久久不卡 | 筱田优av | 中文字幕无线精品亚洲乱码一区 | 丁香婷婷综合激情五月色 | 少妇xxx网站 | 色婷婷香蕉在线一区 | 国产精品久久久久久久久久免费 | 国产91欧美 | 国产成人艳妇aa视频在线 | 在线免费精品 | 综合色导航 | 制服丝袜国产在线 | 黄色小毛片 | 久久爱综合| 亚洲免费综合色在线视频 | 亚洲一级大片 | 少妇二级淫片免费 | 网红日批视频 | 亚洲精品一区二区三区香蕉 | 亚洲一区 中文字幕 | 亚洲成aⅴ人片久青草影院 亚洲无av码一区二区三区 | 国产高潮国产高潮久久久91 | 国产性天天综合网 | 麻豆激情视频 | av在线播放网站 | 久久久亚洲精品一区二区三区 | 无套内射极品少妇chinese | 亚洲淫欲 | 日本熟妇人妻xxxxx-欢迎您 | 亚洲一区h | 二男一女一级一片视频免费 | 欧美鲁鲁 | 高清一区二区三区日本久 | 日韩av伦理 | 毛片网站入口 | 污视频免费在线 | 性高潮久久久久久久 | 国产农村老太xxxxhdxx | 日韩在线一区视频 | 亚洲视频在线免费播放 | 狠狠视频| 经典一区二区 | 国产精品一区二区三区视频免费 | 国产一级啪啪 | 久久久国产精品一区 | 亚洲无线观看国产精品 | 亚洲色图150p | 日韩中文字幕视频 | 七七婷婷婷婷精品国产 | 羞羞答答国产xxdd亚洲精品 | 久久久国产视频 | 色婷婷av一区二区三区之一色屋 | 一区二区看片 | 一交一性一色一伦一区二 | 亚洲综合天堂 | 久久精品视频一区二区三区 | 亚洲无吗在线视频 | 日韩av黄色片| 亚洲国产精品视频 | 日日躁夜夜躁白天躁晚上 | 天堂中文在线观看视频 | 欧美激情图 | 最近中文av字幕在线中文 | 亚洲色成人一区二区三区小说 | 国产精品久久久久久无毒偷食禁果 | 无码人妻精品一区二区三区东京热 | 性欧美一区 | 综合 欧美 亚洲日本 | 亚洲激情视频网 | 黄av在线播放 | av免费在线观 | 国内毛片精品av一二三 | 国产乱色国产精品播放视频 | 老司机在线观看视频 | 丰满少妇毛茸茸做性极端 | jizz偷窥| 日本欧美另类 | 欧美日韩亚洲视频 | www日本黄色 | 91精品久久久久久久久不口人 | 嫩草网站 | 亚洲欧美成人综合 | 欧美肥妇视频 | 男女69式互吃动态图在线观看 | 国产又黄又粗又猛又爽视频 | 黑料av在线 | 亚洲人精品亚洲人成在线 | 蜜桃一本色道久久综合亚洲精品冫 | 中文字幕在线观看一区二区三区 | 亚洲精品久久久中文字幕痴女 | 国产激情在线视频 | 2017天天干 | 欧美粗大猛烈 | 在线人人车操人人看视频 | 国产h自拍 | aaaaa少妇高潮大片在按摩线 | 日韩欧美视频在线 | 精品无码av无码专区 | 粉嫩久久99精品久久久久久夜 | 色av性av丰满av国产 | 亚洲 卡通 欧美 制服 中文 | 色综合久久久久 | 中文字幕久久综合 | 久久泄欲网| 天天干天天舔天天操 | 亚洲一区二区三区久久久 | 一本大道卡一卡二卡三乱码全集资源 | 国产夫妻自拍av | 无码aⅴ精品一区二区三区 45分钟免费真人视频 | 天堂а√在线中文在线 | sese视频在线观看 | 中国人妻被两个老外三p | 7799国产精品久久99 | 人人爽人人爱 | 伊人久久久 | 亚洲美女啪啪 | 国产明星裸体无码xxxx视频 | 最近中文字幕mv | 嫩草av影院 | 日本在线视频www鲁啊鲁 | 51国产视频 | 久久精品成人免费国产片桃视频 | 激情五月色综合国产精品 | www桃色 | 国产精品入口传媒小说 | 国产亚洲精品精品国产亚洲综合 | 韩国三级欧美三级国产三级 | 天天操天天舔天天干 | 午夜精品久久ed2kmp4 | 日本熟妇毛耸耸xxxxxx | а√天堂www在线天堂小说 | 97夜夜澡人人爽人人喊中国片 | 亚洲综合成人亚洲 | 妞妞色www在线精品观看视频 | 800av凹凸视频在线观看 | 娇小性xxxxx极品娇小小说 | 免费涩涩视频 | 可以免费在线观看的av | 大地资源网中文第五页 | 久久免费精品国自产拍网站 | 国产粉嫩av | 精久久久| 欧美日韩在线精品一区二区 | 四虎影视免费在线观看 | a级毛片特级毛片 | 国产精品久久久久久久久福交 | 在线观看av日韩 | 少妇一级1淫片 | av72在线观看 | 爱情岛亚洲论坛入口 | 国产在线视频一区二区三区 | 日韩黄大片 | 欧美精品久久一区二区 | 天天做天天爱夜夜爽少妇 | 日韩午夜免费 | 他揉捏她两乳不停呻吟微博 | 成av人在线观看 | 久久久久久久久99 | 黄色毛片小视频 | 欧洲熟妇精品视频 | 极品少妇xxx | 啄木乌法国一区二区三区 | 亚洲综合视频在线观看 | 久久久久久黄色 | 成人在线综合 | 久久论理| 国产一区二区三区撒尿在线 | 伊人网视频在线观看 | 成人毛片视频网站 | 亚洲图区欧美 | 日本久久久久久久久 | 精品国产一区二区三区久久狼 | 想要xx·m3u8色视频 | 一本一本久久a久久精品综合麻豆 | 国产91精清纯白嫩高中在线观看 | 亚洲免费精品网站 | 日本一级吃奶淫片免费 | 日本黄网站色大片免费观看 | 青草视频在线观看视频 | 椎名空在线观看 | 密臀av夜夜澡人人爽人人 | 四虎影视永久在线观看 | 国产精品99久久久久 | 国产第三区 | 国产精品免费视频二三区 | 中文字幕高清免费日韩视频在线 | 美女裸体跪姿扒开屁股无内裤 | 91av在| 狠狠狠色丁香婷婷综合久久88 | 国产一级黄色片子 | 国产精品永久免费视频 | 人人爽人人爽人人片av亚洲 | 成年人免费看视频 | 91视频中文| 欧美色欧美亚洲高清在线视频 | 一级 黄 色 片69 | 精品国偷自产在线 | 美女av一区 | 新中文字幕 | 亚洲精品女| 两口子交换真实刺激高潮 | 五十岁熟韵母乱视国产 | 99热这| 午夜剧场成人 | 一级一片免费观看 | 日日摸夜夜添夜夜躁好吊 | 精品国产成人一区二区三区 | a在线观看免费网站大全 | 在线观看国产日韩 | 99精品国产在热久久 | 久久精品中文字幕大胸 | 国产性猛交xx乱视频 | 成人性生交片无码免费看 | 在线天堂新版最新版在线8 麻豆成人精品国产免费 | 少妇无套高潮一二三区 | 国产精品一级二级 | 99热久久精品免费精品 | xxx.国产| 亚洲性色图 | 精品成人在线观看 | 免费看毛片网站 | 国产第一页在线观看 | 在线观看波多野结衣 | 亚洲国产日韩在线 | 无码熟妇人妻av | 亚洲精品乱码久久久久久金桔影视 | 少妇饥渴偷公乱第95 | 国内精品久久久久影院优 | 久久久蜜桃 | 日韩欧美成人精品 | 久久久无码人妻精品一区 | 免费在线观看黄色网 | 精品中文字幕av | 免费的又色又爽又黄的片捆绑美女 | 中文免费av | 久久久久久亚洲精品杨幂圣光 | h网址在线观看 | 中文字日产幕码三区的做法大全 | 夜夜爽av福利精品导航 | 国产精品99久久免费 | 无码av波多野结衣久久 | 黄色精品一区二区 | 麻豆高清免费国产一区 | 午夜影院日本 | 日韩精品系列 | 欧洲中文字幕日韩精品成人 | 九一精品在线 | 懂色中文一区二区三区在线视频 | 少妇高潮惨叫正在播放对白 | 欧美性猛交ⅹxx乱大交 | 色撸撸在线观看 | 在线观看国产一级片 | 日韩中文久久 | 日韩女优在线 | 日韩精品a在线观看 | 91免费网 | 黄色av一区 | 蜜臀av首页| 夜添久久精品亚洲国产精品 | 一本色道无码不卡在线观看 | 免费一区二区在线观看 | 欧美性猛交丰臀xxxxx网站 | 国产伦精品一区二区三区四区 | 老汉色av | 成人av时间停止系列在线 | 和粗大男人做爰过程 | 精品国产欧美一区二区 | 亚洲精品国产一区 | 一区二区三区精品国产 | 日本少妇久久 | 亚洲视频在线免费播放 | 欧美成人秋霞久久aa片 | 国产精品岛国久久久久久久久红粉 | 8x8ⅹ国产精品一区二区 | 亚洲第一a在线观看网站 | 国产又黄又猛又粗又爽的a片动漫 | www91自拍| 国产美女特级嫩嫩嫩bbb | 国产一区二区三区在线看 | 永久免费精品精品永久-夜色 | 久久国产精品99久久久久久老狼 | 激情综合色综合啪啪五月丁香 | 亚洲裸男自慰gv网站 | 日本亲子乱子伦xxxx | 国产无遮挡呻吟娇喘视频 | 久草在线中文视频 | 久久精精品久久久久噜噜 | 涩涩资源网 | 国产在线观看无码免费视频 | 色交视频 | 免费韩国羞羞网站视频 | 永久免费精品精品永久-夜色 | 九九热精品视频在线 | 性欧美xxxx | 欧美亚洲高清 | www黄色在线 | 极品少妇xxxx精品少妇偷拍 | 成年人免费网站在线观看 | 日本三级吃奶乳视频在线播放 | 久久午夜无码鲁丝片午夜精品 | 一级色网站| 欧美午夜精品一区二区 | 丰满双乳峰白嫩少妇视频 | 手机在线精品视频 | 日韩欧美性视频 | 亚洲精品视频一二三区 | 色网站在线播放 | 天堂国产一区二区三区四区不卡 | 欧美三级a做爰在线观看 | 日日夜夜免费视频 | 亚洲午夜久久久久 | 国产老熟女网站 | 人成福利视频在线观看 | 老子午夜精品无码 | 久久国产精品-国产精品 | 99热视| 影音先锋成人网 | 四虎最新紧急入口 | 美女久久精品 | 国产精品麻豆色哟哟av | 国产中文字幕一区二区 | 女人被做到高潮视频 | 久草在线在线精品观看 | 337p粉嫩大胆噜噜噜 | 女同性久久产国女同久久98 | 理论视频在线观看 | 在线超碰| 亚洲欧美日韩国产精品一区二区 | 欧美午夜性春猛交 | 1769国产| 天堂亚洲 | 五月天综合激情网 | 97久久久久久久 | 成人在线观看av | 国产91综合一区在线观看 | 成人动漫视频在线观看 | 午夜a区 | 真人祼交二十三式视频 | 成人99视频 | √天堂资源在线中文最新版 | 成人做爰高潮片免费视频 | 免费国产在线观看麻豆 | 999精品国产 | 性史性高校dvd毛片 性视频黄色 | 日韩顶级毛片 | 亚洲精品二 | 蜜臀av午夜一区二区三区 | 欧美一区二区三区四区五区六区 | xxx国产在线观看 | 麻豆精品免费观看 | 性猛交波兰xxxxx | 日本最新偷拍小便视频 | 国产精品成人免费一区久久羞羞 | 青青久久国产 | 一级 黄 色 毛片 | 3级黄色片| 色婷婷久久一区二区三区麻豆 | 国产黄大片 | 午夜性刺激免费视频 | 色欲精品国产一区二区三区av | 国产精品一区二区久久久 | av观看国产| 91国产在线看 | 九九re6热在线视频精品66 | 国产精品情侣呻吟对白视频 | 少妇高潮一区二区三区 | 俄罗斯小14粉嫩呦萝 | 大陆熟妇丰满多毛xxxⅹ | 亚洲 另类 熟女 字幕 | 波多野结衣美乳人妻hd电影欧美 | 亚洲国产精品久久网午夜 | 白嫩少妇bbw撒尿视频 | 欧美日韩精品在线观看视频 | 色噜噜狠狠一区 | 夜夜骑夜夜| 久久和欧洲码一码二码三码 | 婷婷色婷婷开心五月四房播播 | 麻豆国产va免费精品高清在线 | 国产成人无码18禁午夜福利p | 成人免费视频在线播放 | 欧美69式性猛交 | 亚洲va欧美va人人爽春色影视 | 国产超高清麻豆精品传媒麻豆精品 | 深夜福利网| 国产你懂得 | 亚洲性激情 | 麻豆传媒一区 | 国产成人精品一区二三区 | 日韩 欧美 自拍 | 亚洲精品一区二区三区四区五区 | 人人妻人人澡人人爽超污 | 本道综合精品 | 亚洲福利网址 | 国产乱视频在线观看 | 中文字幕第12页 | 97超级碰碰碰 | 黄色av网页 | 色噜噜综合 | 精品人人 | 西方裸体在线观看 | 国产精品网友自拍 | 亚洲一区成人 | 91青青草 | 亚洲免费永久精品 | 亚洲爆乳精品无码一区二区 | 国产大片一区二区三区 | 精品国产乱码久久久久久久 | 欧美日韩精品乱国产 | 牛牛av在线 | 狠狠色综合色综合网络 | 国产亚洲精品久久久久久青梅 | 黄色片久久久久 | 日韩精品免费在线视频 | 天干天干天啪啪夜爽爽99 | 国精品产品区三区 | 久久亚洲sm情趣捆绑调教 | 成人毛片18女人毛片免费 | 免费全部高h视频无码 | 最新国产精品久久精品 | 国产人妻久久精品二区三区特黄 | 中文字幕无人区二 | 免费在线观看av网址 | 国产无遮挡又黄又爽免费网站 | 亚洲图片自拍偷拍 | 亚洲欧美国产精品久久 | 男女一进一出粗大楱视频 | 美女销魂一区二区 | 丝袜人妻一区二区三区网站 | 岛国片在线播放97 | 免费人成激情视频在线观看冫 | 亚洲丶国产丶欧美一区二区三区 | 综合 欧美 亚洲日本 | 综合一区二区三区 | 久久爱成人 | 无码人妻品一区二区三区精99 | 日韩啪啪片 | 94av| 极品毛片 | 亚洲 自拍 另类 欧美 丝袜 | 91毛片网| 国产猛烈高潮尖叫视频免费 | 91精品无人成人www | www午夜视频| 秋霞午夜网| 中国老熟女重囗味hdxx | 性做久久久久久久 | 韩国午夜理伦三级2020苹果 | 亚洲免费黄色 | 久久看av| 日韩高清dvd| 精品久久一 | 日韩黄色三级视频 | 红桃色av| 国内精品小视频 | 欧美猛少妇色xxxxx | 国产女人被狂躁到高潮小说 | 天堂网日本 | 91欧美精品 | 精品欧美一区二区精品久久久 | 久久婷婷色一区二区三区asmr | 成人国产精品色哟哟 | 91超薄丝袜肉丝一区二区 | 国产在线精品播放 | 午夜免费视频网站 | 国产69精品久久久久毛片 | 一本到亚洲网 | 国产黄色片免费观看 | 日韩欧美一区二区视频 | 精品久久99 | 久久国产精品-国产精品 | 色呦呦视频在线观看 | 亚洲一卡一卡二新区无人区 | 99国产热| 国产乱xxxxx97国语对白 | 亚洲老女人av | 北条麻妃在线一区二区免费播放 | 亚洲精品成人区在线观看 | 91视频一区二区三区 | 国产亚av手机在线观看 | 嫩草社区 | 日本精品一区二区三区在线观看 | 在线超碰91 | 69re视频| 女性无套免费网站在线看动漫 | 色婷婷六月 | 久久黄页 | 欧美肥胖老太videossexohd | 欧美日本免费一区二区三区 | 天堂躁躁人人躁婷婷视频ⅴ | 国产成人午夜福利在线观看 | av在线天堂网 | 亚洲日韩一页精品发布 | 国产素人自拍 | 九色精品 | 欧产日产国产精品乱噜噜 | 国产精品久久久久久福利一牛影视 | 暖暖日本在线 | 麻豆国产露脸在线观看 | 国产清纯在线一区二区 | 国产无套粉嫩白浆内的人物介绍 | 丰满人妻在公车被猛烈进入电影 | 国产偷久久一级精品60部 | 99久久精品日本一区二区免费 | 国产精品27p | 色视频网 | 欧美一级性视频 | 亚洲欧美日韩中文高清www777 | 337p粉嫩大胆噜噜噜亚瑟影院 | 欧美视频在线观看一区二区 | 久久婷婷成人综合色综合 | 亚洲国产精品色拍网站 | 久久精品网址 | 欧美一区二区三区精品 | 国产成a人片在线观看视频下载 | 国产乱码字幕精品高清av | 天天国产视频 | 精品亚洲欧美高清在线观看 | 又黄又爽又高潮免费毛片 | 中文字幕一区二区三区四区 | 婷婷四房综合激情五月在线 | 99视频观看| 亚州av在线播放 | 夫の友人 风间ゆみ 在线 | 亚洲欧美一区二区三区视频 | 香蕉伊蕉伊中文视频在线 | 亚洲中文字幕av在天堂 | 日韩免费大片 | 国产精品综合久久久久久 | 97资源共享在线视频 | 影音先锋中文字幕在线播放 | 99re国产精品视频 | 黄色片91| 国产不卡一区二区视频 | 美女隐私黄www网站免 | 精品黄色在线观看 | 免费无码av片在线观看中文 | 国产成人61精品免费看片 | 中文字幕一区在线 | 中文字幕在线播放一区 | 欧洲色视频 | 日韩视频成人 | 大屁股大乳丰满人妻 | 久久免费看a级毛毛片 | 69热在线观看 | 97色伦图片97综合影院 | 暖暖视频日本 | 暖暖日本在线观看 | 欧美最顶级丰满的aⅴ艳星 欧美最黄视频 | 忍不住的亲子中文字幕 | 精品一区二区三区波多野结衣 | 屁屁影院一区二区三区 | 亚洲精品日韩av | 国产一区二区黄 | 久久国产劲暴∨内射 | 阿v天堂2018 阿v天堂在线 | 中文字幕一区二区人妻 | 久久国产自偷自偷免费一区调 | 亚洲乱码在线观看 | 欧美黄大片 | 日韩免费无码一区二区视频 | 国产精品专区在线观看 | 国产99久久久国产精品潘金 | 国产色片在线观看 | 玩丰满高大邻居人妻无码 | 欧美三级手机在线观看 | 91视频网址入口 | 精品人妻少妇一区二区 | 亚洲精品久久久久国产 | 91视频成人 | 色噜噜狠狠一区二区三区果冻 | 91高清在线视频 | 国产极品在线观看 | 伊人久久一区二区 |

    電子發燒友

    中國電子工程師最喜歡的網站

    • 2931785位工程師會員交流學習
    • 獲取您個性化的科技前沿技術信息
    • 參加活動獲取豐厚的禮品