非对称多处理(AMP)允许多处理器系统运行彼此独立的多个操作系统(OS)。换句话说,每个CPU都有自己的专用内存空间,其中包含要在该CPU上运行的操作系统和应用程序。此外,可能会有一些共享内存空间用于多处理器通信。这与对称多处理(SMP)形成对比,在对称多处理(SMP)中,一个OS使用公共共享内存空间在多个CPU上运行。
本教程是飞思卡尔P4080处理器最新的研究结果,如果你不熟悉此芯片,可以读一读它的手册,它是PowerPC系列中的8核处理器。(手册超过3500页)
下图显示了典型的AMP系统。CPU0启动后,将使用wrload实用程序将文件系统中的特定VxWorks映像加载到目标CPU的内存空间中。CPU 0拥有较大的可用内存空间,而其他CPU的可用区域较小。
AMP也有两种不同的类型,有监督型的(hypervisor)和非监督型的。本文仅涉及非监督型的AMP。系统管理程序是一个完全不同的范畴。
为什么使用AMP
AMP适用于可以拆分为逻辑模块的应用程序(例如路由器中的控制平面和数据平面的处理),或者在某些处理器上需要提高安全性的级别(将设备分配给处理器,因此IO连接和安全应用程序可以由MMU分开)。此外,可以将完全不同的OS加载到CPU,因此你可能需要Linux和vxWorks的不同版本的混合。
AMP还可以通过将多个板卡合并到单个板卡上来帮助你升级旧系统,通过将运行在旧板卡上的旧应用程序移植到多处理器系统中的某一个CPU上,系统设计可以保持不变,并且移植变得更加简单,通过使用AMP,无需将所有应用程序代码合并到单个代码空间中。使用多进程通信,网络设备(MND)甚至可以保留现有的以太网连接,而无需进行任何更改。
在VXWORKS中建立AMP
你可以使用两种方式来构建AMP的VxWorks映像,即使用WindRiver Workbench(GUI)或使用命令行。使用Workbench的麻烦在于,对于8个CPU,您必须分别配置八个VxWorks映像,这非常繁琐。其实,我们可以在workspace中创建一个像这样的makefile:
###############################################################################
#
# makefile for eb718 AMP builds
#
#
# https://www.gaitpu.com
#
# This makefile demonstrates how to build an AMP system for the
# Kontronn eb718 board. This board uses an 8 core Freescale P4080 Chip
#
# From a vxWorks development shell, type make amp. VxWorks images will be copied
# into FTP_DIR
#
# for Windows hosts, fix slashes
WIND_HOME := $(subst \,/,$(WIND_HOME))
WIND_BASE := $(subst \,/,$(WIND_BASE))
WIND_USR := $(subst \,/,$(WIND_USR))
TOOL = gnu
# all vxWorks images will get copied here for pickup
FTP_DIR = C:/temp/incoming
AMP0_DIR = amc718_gnu_amp0
AMP0_PROJ = $(AMP0_DIR)/$(AMP0_DIR).wpj
AMP1_DIR = amc718_gnu_amp1
AMP1_PROJ = $(AMP1_DIR)/$(AMP1_DIR).wpj
AMP2_DIR = amc718_gnu_amp2
AMP2_PROJ = $(AMP2_DIR)/$(AMP2_DIR).wpj
AMP3_DIR = amc718_gnu_amp3
AMP3_PROJ = $(AMP3_DIR)/$(AMP3_DIR).wpj
AMP4_DIR = amc718_gnu_amp4
AMP4_PROJ = $(AMP4_DIR)/$(AMP4_DIR).wpj
AMP5_DIR = amc718_gnu_amp5
AMP5_PROJ = $(AMP5_DIR)/$(AMP5_DIR).wpj
AMP6_DIR = amc718_gnu_amp6
AMP6_PROJ = $(AMP6_DIR)/$(AMP6_DIR).wpj
AMP7_DIR = amc718_gnu_amp7
AMP7_PROJ = $(AMP7_DIR)/$(AMP7_DIR).wpj
amp: amp0 amp1 amp2 amp3 amp4 amp5 amp6 amp7
amp0:
vxprj create -force $(BSP) $(TOOL) $(AMP0_PROJ)
vxprj bundle add $(AMP0_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP0_PROJ) BUNDLE_AMP_PRI
vxprj component add $(BSP_PROJ) INCLUDE_PCI_BUS
vxprj build $(AMP0_PROJ)
cp $(AMP0_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.0
amp1:
vxprj create -force $(BSP) $(TOOL) $(AMP1_PROJ)
vxprj bundle add $(AMP1_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP1_PROJ) BUNDLE_AMP_SEC
vxprj component add $(AMP1_PROJ) INCLUDE_AMP_CPU_01
# need to remove INCLUDE_WDB_SYS, incompatible with AMP
vxprj component remove $(AMP1_PROJ) INCLUDE_WDB_SYS
vxprj build $(AMP1_PROJ)
cp $(AMP1_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.1
amp2:
vxprj create -force $(BSP) $(TOOL) $(AMP2_PROJ)
vxprj bundle add $(AMP2_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP2_PROJ) BUNDLE_AMP_SEC
vxprj component add $(AMP2_PROJ) INCLUDE_AMP_CPU_02
# need to remove INCLUDE_WDB_SYS, incompatible with AMP
vxprj component remove $(AMP2_PROJ) INCLUDE_WDB_SYS
# remove networking. No devices
vxprj component remove $(AMP2_PROJ) INCLUDE_NETWORK
vxprj build $(AMP2_PROJ)
cp $(AMP2_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.2
amp3:
vxprj create -force $(BSP) $(TOOL) $(AMP3_PROJ)
vxprj bundle add $(AMP3_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP3_PROJ) BUNDLE_AMP_SEC
vxprj component add $(AMP3_PROJ) INCLUDE_AMP_CPU_03
# need to remove INCLUDE_WDB_SYS, incompatible with AMP
vxprj component remove $(AMP3_PROJ) INCLUDE_WDB_SYS
# remove networking. No devices
vxprj component remove $(AMP3_PROJ) INCLUDE_NETWORK
vxprj build $(AMP3_PROJ)
cp $(AMP3_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.3
amp4:
vxprj create -force $(BSP) $(TOOL) $(AMP4_PROJ)
vxprj bundle add $(AMP4_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP4_PROJ) BUNDLE_AMP_SEC
vxprj component add $(AMP4_PROJ) INCLUDE_AMP_CPU_04
# need to remove INCLUDE_WDB_SYS, incompatible with AMP
vxprj component remove $(AMP4_PROJ) INCLUDE_WDB_SYS
# remove networking. No devices.
vxprj component remove $(AMP4_PROJ) INCLUDE_NETWORK
vxprj build $(AMP4_PROJ)
cp $(AMP4_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.4
amp5:
vxprj create -force $(BSP) $(TOOL) $(AMP5_PROJ)
vxprj bundle add $(AMP5_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP5_PROJ) BUNDLE_AMP_SEC
vxprj component add $(AMP5_PROJ) INCLUDE_AMP_CPU_05
# need to remove INCLUDE_WDB_SYS, incompatible with AMP
vxprj component remove $(AMP5_PROJ) INCLUDE_WDB_SYS
# remove networking. No devices.
vxprj component remove $(AMP5_PROJ) INCLUDE_NETWORK
vxprj build $(AMP5_PROJ)
cp $(AMP5_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.5
amp6:
vxprj create -force $(BSP) $(TOOL) $(AMP6_PROJ)
vxprj bundle add $(AMP6_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP6_PROJ) BUNDLE_AMP_SEC
vxprj component add $(AMP6_PROJ) INCLUDE_AMP_CPU_06
# need to remove INCLUDE_WDB_SYS, incompatible with AMP
vxprj component remove $(AMP6_PROJ) INCLUDE_WDB_SYS
# remove networking. No devices.
vxprj component remove $(AMP6_PROJ) INCLUDE_NETWORK
vxprj build $(AMP6_PROJ)
cp $(AMP6_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.6
amp7:
vxprj create -force $(BSP) $(TOOL) $(AMP7_PROJ)
vxprj bundle add $(AMP7_PROJ) BUNDLE_STANDALONE_SHELL
vxprj bundle add $(AMP7_PROJ) BUNDLE_AMP_SEC
vxprj component add $(AMP7_PROJ) INCLUDE_AMP_CPU_07
# need to remove INCLUDE_WDB_SYS, incompatible with AMP
vxprj component remove $(AMP7_PROJ) INCLUDE_WDB_SYS
# remove networking. No devices.
vxprj component remove $(AMP7_PROJ) INCLUDE_NETWORK
vxprj build $(AMP7_PROJ)
cp $(AMP7_DIR)/default/vxWorks $(FTP_DIR)/vxWorks.7
使用WRLOAD
wrload实用程序在第一个cpu(cpu0)的vxWorks shell上执行,它将从已挂载的文件系统中加载vxWorks映像,将代码和数据加载到目标cpu上,然后将.bss段清零。我发现它对连续的加载可能很敏感,因此我倾向于在调用之间放一些taskDelays,另外,vxWorks需要某种引导行,并且缺少引导行参数时响应不佳。请参阅以下示例:
wrload ("-file host:/vxWorks.1 -cpu 1 -tsym \"*sysBootLine=dtsec(1,1) host:/vxWorks.1 h=192.168.1.100 e=192.168.1.51\" ");
taskDelay (60);
wrload ("-file host:/vxWorks.2 -cpu 2 -tsym \"*sysBootLine=dtsec(2,2) \" ");
taskDelay (60);
使用‘TIP’命令在一个CPU上得到一个SHELL
tip是一项新功能,可通过MSD(MIPC串行设备)连接到其他CPU,从而可以在没有物理串行连接的地方建立外壳。BSP会自动创建MSD连接:
-> devs
drv name
0 /null
1 /tyCo/0
1 /tyCo/1
1 /ttyMsd0
1 /ttyMsd1
1 /ttyMsd2
1 /ttyMsd3
1 /ttyMsd4
1 /ttyMsd5
1 /ttyMsd6
要将CPU1和CPU2连接起来(第一个msd连接msd0将连接到cpu1):
tip ("dev=/ttyMsd0", "dev=/ttyMsd1")
~?
[Available commands]
~.: Drop connection and exit
~l: List available sessions
~s: Switch session
~?: Print command summary