




已阅读5页,还剩31页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Windows CE 6.0 启动过程分析在Windows CE 6.0中,内核(Kenerl)和OEM代码被分成oal.exe、kernel.dll和kitl.dll三个部分,其中启动代码(startup)和 OAL层的实现部分不再与内核链接生成NK.exe,取而代之的是启动代码(startup)和硬件相关且独立于内核的OAL层的实现部分编译成 oal.exe,而与内核相关且独立于硬件的OAL层代码包含在kernel.dll中;内核无关传输层(KITL)的支持代码从OAL层分离出来编译成 kitl.dll。 从表面上看,好像只是代码重新组合了一下,从帮助文档中BSP的移植过程看好像也是这么一回事,实际上,整个Windows CE 6.0内核布局发生了很大的改变。Windows CE 6.0的启动过程也是如此,如果你想按照Windows CE 5.0的启动顺序去分析Windows CE 6.0的启动顺序,可能会走到一个死胡同。主要是因为Windows CE 6.0在启动过程中调用了kernel.dll和kitl.dll两个动态链接库的原因,而且Windows CE6.0不再编译生成KernKitlProf.exe内核文件。 从Windows CE 6.0的帮助文档可以看出,WinCE6.0的启动只与oal.exe和kernel.dll有关,至于kitl.dll,只有将操作系统编译成具有 KITL功能时才用到。分析Windows CE 6.0的启动过程实际上找到编译oal.exe和kernel.dll的源码位置。 首先看一下将WinCE6.0编译成诸如WinCE5.0所说的基本内核情况,即kern.exe。对于oal.exe源码位置比较容易找到,因为 oal.exe是启动代码与硬件相关的OAL层实现文件编译而成,所以只需在BSP的OAL目录中便能找到。而对于kernel.dll,在BSP目录结构中,基本上无法找到kernel.dll的编译文件,所以必须从其他方面着手。 下面为WinCE 6.0的编译日志输出文件:makeimg.out在文件复制过程的一部分:Copying E:WINCE600OSDesignsxsbase270xsbase270RelDirXSBase270_ARMV4I_Releaseoal.exe toE:WINCE600OSDesignsxsbase270xsbase270RelDirXSBase270_ARMV4I_Releasenk.exe for debugger Copying E:WINCE600OSDesignsxsbase270xsbase270RelDirXSBase270_ARMV4I_Releasekern.dll toE:WINCE600OSDesignsxsbase270xsbase270RelDirXSBase270_ARMV4I_Releasekernel.dll for debugger 从日志输出文件可以看出,在文件复制过程中,WinCE6.0编译器将oal.exe更名为nk.exe,而将kern.dll文件更名为 kernel.dll,也就是说,kern.dll文件的实现部分就是kernel.dll的实现体。根据前面的分析,oal.exe是与硬件相关独立于内核的OAL层的实现部分,而kernel.dll为内核相关独立于硬件的OAL层的实现部分。同样可以从最后整合后的二进制配置文件ce.bib文件中看出端倪。; CESYSGEN IF CE_MODULES_NKnk.exe E:WINCE600OSDesignsxsbase270xsbase270RelDirXSBase270_ARMV4I_Releaseoal.exe NK SHZkitl.dll E:WINCE600OSDesignsxsbase270xsbase270RelDirXSBase270_ARMV4I_Releasekitl.dll NK SHZkernel.dll E:WINCE600OSDesignsxsbase270xsbase270RelDirXSBase270_ARMV4I_Releasekern.dll NK SHZ; CESYSGEN ENDIF 而kern.dll动态库在整个Windows CE6.0中没有显式编译过程,即没有一个sources文件有kern.dll的编译过程,所以只能从操作系统的编译文件Makefile中寻找其编译过程。下面看一下$(_PUBLICROOT)commonCESYSGENmakefile中的部分内容:nk:$(NK_COMPONENTS) $(NK_REPLACE_COMPONENTS)copy $(SG_INPUT_LIB)oemstub.pdb $(SG_OUTPUT_OAKLIB)copy $(SG_INPUT_LIB)oemstub.lib $(SG_OUTPUT_OAKLIB)set TARGETTYPE=DYNLINKset TARGETNAME=kernset RELEASETYPE=OAKset DLLENTRY=NKStartupset DEFFILE=NO_DEF_FILEset TARGETLIBS=set SOURCELIBS=%NKLIBS% $(SG_INPUT_LIB)nkmain.lib $(SG_INPUT_LIB)fulllibc.lib$(MAKECMD) /NOLOGO NOLIBC=1 kern.dll 从上述代码中可以发现,原来kern.dll动态库是从oemstub.lib编译而来,而且与nkmain.lib有关。 在理顺了上述文件的相互之间的关系之后,再来分析Windows CE 6.0的启动过程可能就比较容易啦。 在理清了上述文件的关系之后,便可以分析任意一款基于ARM微处理器的Windows CE 6.0的启动过程,现在以深圳亿道电子技术有限公司开发的基于PXA270 ARM开发平台为例,分析Windows CE 6.0操作系统启动过程。1、Startup函数: 从Windows CE 6.0的帮助文档可以看出,WinCE6.0的启动只与oal.exe和kernel.dll有关,至于kitl.dll,只有将操作系统编译成具有 KITL功能时才用到。分析Windows CE 6.0的启动过程实际上找到编译oal.exe和kernel.dll的源码位置。oal.exe 的通过Startup函数完成硬件的初始化。Startup.s代码与该硬件平台的Bootloader启动代码共用,其中PreInit 函数主要完成将ARM处理器工作模式切换到管理员模式、同时关闭MMU,并检测系统启动原因,如果是热启动、即在该函数调用之前已经启动了 Bootloader程序,相当基本硬件初始化已经完成,则直接跳转到OALStartUp函数中;否则需要进行硬件中断屏蔽、内存、系统时钟频率、电源管理等硬件的基本初始化过程。(具体过程见代码的分析)$(_PLATFORMROOT)xsbase270srccommonStartupStartup.sLEAF_ENTRY StartUp bl PreInit tst r10, #RCSR_HARD_RESET beq OALStartUp tst r10, #RCSR_GPIO_RESET bne Continue_StartUp bl xlli_mem_init ;初始化内存控制器 ldr r0, =xlli_PMRCREGS_PHYSICAL_BASE; ldr r0, r0, #xlli_PSPR_offset; mov r1, r10; bl XllpPmValidateResumeFromSleep; cmp r0, #0; bne Failed_Sleep_Resume; Sleep_Reset ldr r0, =xlli_PMRCREGS_PHYSICAL_BASE; ldr r0, r0, #xlli_PSPR_offset; mov r1, r10; b XllpPmGoToContextRestoration; Failed_Sleep_Resume ldr r1, =xlli_RCSR_SMR bic r10, r10, r1 Continue_StartUp bl xlli_intr_init; ;初始化中断控制器 bl EnableClks; ;使能内核时钟(内存/OS定时器/FFART时钟之需) bl OALXScaleSetFrequencies ;设置系统频率 bl xlli_mem_Topt bl xlli_mem_restart ;复位内存,使其处于工作模式 bl xlli_ost_init ;初始化操作系统定时器 bl xlli_pwrmgr_init ;初始化电源管理 bl xlli_IMpwr_init ;初始化内部存储器 bENTRY_END2、OALStartUp函数: 在系统硬件初始化完毕之后,Startup调用OALStartUp函数,OALStartUp函数主要完成将OEMAddressTable表传递给内核;然后调用KernelStart函数跳转到内核OEMAddressTable表的主要作用表的每一个入口都定义了一个内存中的物理位置、内存的大小以及映射这物理地址的静态虚拟地址;静态虚拟内存地址被定义在缓冲存储器的范围之内;内核可以创建非缓冲的内存地址指向到相同的物理地址;对于同一物理地址,既有一个缓冲的虚拟内存地址,也有一个非缓冲的虚拟内存地址;OEMAddressTable最后必须以0结尾;对于MIPS和SHx类型的CPU,物理地址与虚拟地址的映射由CPU完成,无需创建OEMAddressTable$(_PLATFORMROOT)xsbase270srcInc Oemaddrtab_cfg.inc):ALIGN g_oalAddressTable DCD 0x80000000, 0xA0000000,64; XSBASE270: SDRAM (64MB). DCD 0x84000000, 0x5C000000,1; BULVERDE: Internal SRAM (64KB bank 0). DCD 0x84100000, 0x58000000,1; BULVERDE: Internal memory PM registers. DCD 0x84200000, 0x4C000000,1; BULVERDE: USB host controller. DCD 0x84300000, 0x48000000,1; BULVERDE: Memory controller. DCD 0x84400000, 0x44000000,1; BULVERDE: LCD controller. DCD 0x84500000, 0x40000000,32; BULVERDE: Memory-mapped registers DCD 0x86500000, 0x00000000,64; XSBASE270: nCS0: Boot Flash (64MB). DCD 0x96600000, 0x3C000000,64; BULVERDE: PCMCIA S1 common memory space. DCD 0x8A600000, 0x38000000,32; BULVERDE: PCMCIA S1 attribute memory space. DCD 0x8C600000, 0x30000000,32; BULVERDE: PCMCIA S1 I/O space. DCD 0x8E500000, 0x2C000000,64; BULVERDE: PCMCIA S0 common memory space. DCD 0x92500000, 0x28000000,32; BULVERDE: PCMCIA S0 attribute memory space. DCD 0x94500000, 0x20000000,32; BULVERDE: PCMCIA S0 I/O space. DCD 0x96500000, 0xE0000000,1; XSBASE270: Zero-bank . DCD 0x96600000, 0x14000000,1; XSBASE270: nCS5: eXpansion board header. DCD 0x96600000, 0x10000000,64; XSBASE270: nCS4: USB2.0/IDE controller. DCD 0x9A700000, 0x0C000000,1; XSBASE270: nCS3: SMSC 91C111 Ethernet controller. DCD 0x9A800000, 0x0A000000,1; XSBASE270: nCS2 : Board registers (CPLD). DCD 0x9A900000, 0x04000000,32; XSBASE270: nCS1: Secondary flash (32MB). DCD 0x9F900000, 0x50000000,1; BULVERDE: Camera peripheral interface. DCD 0x9FA00000, 0x14700000,1 DCD 0x00000000, 0x00000000,0;end of tableEND$(_PLATFORMROOT)xsbase270srcoalOalLibStartup.sALIGNLEAF_ENTRY OALStartUp add r0, pc, #g_oalAddressTable - (. + 8) mov r11, r0 b KernelStart nop nop nop nop nop nop STALL b STALL ;Spin forever.3、KernelStart函数主要作用:完成OEMAddressTable表中的物理地址到虚拟地址和虚拟地址到物理地址之间的映射;对存储器页表和内核参数区存储空间(RAM或DRAM)进行清零处理。读出CPU的ID号,内核需要根据该ID决定ARM的MMU处理,因为ARMV6和ARMV6之前的ARM处理器的MMU处理过程有所区别;设置并开启MMU和Cache,因为在Startup函数关闭MMU和Cache; 设置ARM处理器工作模式的SP指针,ARM处理器共用7种不同的工作模式(USER、FIQ、IRQ、Supervisor、Abort、 Undefined、System),除用户模式(USER)和系统模式(System)之外,其他5种工作模式都有具有特定的SP指针寄存器(ARM处理器称其为影子寄存器);读取内核启动所需要的KDataStruct结构体;调用ARMInit函数重新定位Windows CE内核参数pTOC和初始化OEMInitGlobals全局变量;利用mov pc, r12指令跳转到kernel.dll的入口位置,即NKStartup函数中。$(_PRIVATEROOT)WINCEOSCOREOSNKLDRARMarmstart.sLEAF_ENTRY KernelStart mov r11, r0 ;(r11) = &OEMAddressTable (save pointer) mov r1, r11 ;(r1) = &OEMAddressTable (2nd argument to VaFromPa) bl VaFromPa mov r6, r0 ;(r6) = VA of OEMAddressTable ; convert base of PTs to Physical address ldr r4, =PTs ;(r4) = virtual address of FirstPT mov r0, r4 ;(r0) = virtual address of FirstPT mov r1, r11 ;(r1) = &OEMAddressTable (2nd argument to PaFromVa) bl VaFromPa mov r10, r0 ;(r10) = ptr to FirstPT (physical) ; Zero out page tables & kernel data page mov r0, #0 ;(r0-r3) = 0s to store mov r1, #0 mov r2, #0 mov r3, #0 mov r4, r10 ; (r4) = first address to clear add r5, r10, #KDEnd-PTs ; (r5) = last address + 118 stmia r4!, r0-r3 stmia r4!, r0-r3 cmp r4, r5 blo %B18 ; read the architecture information bl GetCpuId mov r5, r0 LSR #16 ; r5 = 16 and r5, r5, #0x0000000f ; r5 &= 0x0000000f = architecture id add r4, r10, #HighPT-PTs ; (r4) = ptr to high page table cmp r5, #ARMv6 ; v6 or later? ; ARMV6_MMU orrge r0, r10, #PTL2_KRW + PTL2_SMALL_PAGE + ARMV6_MMU_PTL2_SMALL_XN ; (r0) = PTE for 4K, kr/w u-/- page, uncached unbuffered, nonexecutable ; PRE ARMV6_MMU; orrlt r0, r10, #PTL2_KRW + (PTL2_KRW 2) + (PTL2_KRW 4) + (PTL2_KRW 6) ;Need to replicate AP bits into all 4 fields orrlt r0, r0, #PTL2_SMALL_PAGE + PREARMV6_MMU_PTL2_SMALL_XN ;(r0) = PTE for 4K, kr/w u-/- page, uncached unbuffered, nonexecutable str r0,r4, #0xD0*4 ;store the entry into 4 slots to map 16K of primary page table add r0,r0, #0x1000 ;step on the physical address str r0,r4, #0xD1*4 add r0,r0, #0x1000 ;step on the physical address str r0,r4, #0xD2*4 add r0,r0, #0x1000 ;step on the physical address str r0,r4, #0xD3*4 add r8,r10, #ExceptionVectors-PTs ;(r8) = ptr to vector page orr r0,r8, #PTL2_SMALL_PAGE ;construct the PTE (C=B=0) cmp r5,#ARMv6 ;v6 or later? ; ARMV6_MMU orrge r0, r0, #PTL2_KRW ; PRE ARMV6_MMU orrlt r0, r0, #PTL2_KRW + (PTL2_KRW 2) + (PTL2_KRW 4) + (PTL2_KRW 6) ; Need to replicate AP bits into all 4 fields for pre-V6 MMU str r0,r4, #0xF0*4 ;store entry for exception stacks and vectors ;other 3 entries now unused add r9,r10,#KPage-PTs ;(r9) = ptr to kdata page orr r0,r9,#PTL2_SMALL_PAGE ;(r0)=PTE for 4K (C=B=0) ; ARMV6_MMU (condition codes still set) orrge r0, r0, #PTL2_KRW_URO ; No subpage access control, so we must set this all to kr/w+ur/o ; PRE ARMV6_MMU orrlt r0, r0, #(PTL2_KRW 0) + (PTL2_KRW 2) + (PTL2_KRW_URO 4) ;(r0) = set perms kr/w kr/w kr/w+ur/o r/o str r0, r4, #0xFC*4 ;store entry for kernel data page orr r0,r4, #PTL1_2Y_TABLE ;(r0) = 1st level PTE for high memory section add r1, r10, #0x4000 str r0, r1, #-4 ; store PTE in last slot of 1st level table add r10, r10, #0x2000 ; (r10) = ptr to 1st PTE for unmapped space mov r0, #PTL1_SECTION orr r0, r0, #PTL1_KRW ;(r0)=PTE for 0: 1MB (C=B=0, kernel r/w)20 mov r1, r11 ;(r1) = ptr to OEMAddressTable array (physical)25 ldr r2,r1,#4 ;(r2) = virtual address to map Bank at ldr r3,r1,#4 ;(r3) = physical address to map from ldr r4,r1,#4 ;(r4) = num MB to map cmp r4,#0 ;End of table? beq %F29 ldr r12, =0x1FF00000 and r2, r2, r12 ;VA needs 512MB, 1MB aligned. ldr r12, =0xFFF00000 and r3, r3, r12 ;PA needs 4GB, 1MB aligned. add r2, r10, r2, LSR #18 add r0, r0, r3 ;(r0) = PTE for next physical page28 str r0, r2,#4 add r0, r0, #0x00100000 ;(r0) = PTE for next physical page sub r4, r4, #1 ;Decrement number of MB left cmp r4, #0 bne %B28 ;Map next MB bic r0, r0,#0xF0000000 ;Clear Section Base Address Field bic r0, r0, #0x0FF00000 ;Clear Section Base Address Field b %B25 ;Get next element29 sub r10, r10, #0x2000 ;(r10) = restore address of 1st level page table ldr r12, =0xFFF00000 ;(r12) = mask for section bits and r1, pc, r12 ;physical address of where we are ;NOTE: we assume that the KernelStart function never spam across 1M boundary. orr r0, r1, #PTL1_SECTION orr r0, r0, #PTL1_KRW ;(r0) = PTE for 1M for current physical address, C=B=0, kernel r/w add r7, r10, r1, LSR #18 ;(r7) = 1st level PT entry for the identity map ldr r8, r7 ;(r8) = saved content of the 1st-level PT str r0, r7 ;create the identity map mov r1, #1 mtc15 r1, c3 ;Setup access to domain 0 and clear other mtc15 r10, c2 ;setup translation base (physical of 1st level PT) mov r0, #0 mcr p15, 0, r0, c8, c7, 0 ;Flush the I&D TLBs mfc15 r1, c1 orr r1, r1, #0x007F ;changed to read-mod-write for ARM920 Enable: MMU, Align, DCache, WriteBuffer cmp r5, #ARMv6 ;r5 still set ; ARMV6_MMU orrge r1, r1, #0x3000 ;vector adjust, ICache orrge r1, r1, #1dwTOCAddr = (DWORD) pTOC; pKData-dwOEMInitGlobalsAddr = (DWORD) OEMInitGlobals; SetOsAxsDataBlockPointer(pKData); return FindKernelEntry (pTOC);5、NKStartup函数: 硬件平台初始化完成后,oal.exe的启动任务基本完成,余下的启动工作由内核相关且独立于内核的OAL层实现体kernel.dll接管。kernel.dll主要作用:从结构体参数KDataStruct * pKData提取内核启动时所必须的全局变量,同时初始化内核全局变量; 定位对Windows CE 6.0特有的OEMGLOBAL结构体的初始化函数OEMInitGlobals地址,该结构体构建了内核和OAL层之间进行通信的桥梁。在 OEMGLOBAL结构体定义了OAL层所必须的函数,该结构体在oemglobal.c文件中被初始化,并被编译在OEMMain.lib和 OEMMain_StaticKITL.lib两个库中,如果OAL链接这两个库,则必须要有该结构体中函数实现体;通过调用ARMSetup设置物理地址和非缓冲的虚拟内存地址的映射、ARM中断向量以及内核模式所需要的堆栈。调用OEMInitDebugSerial函数初始化调试串口;调用OEMInit进行平台初始化; 需要注意的时,NKStartup函数调用OEMInitDebugSerial和OEMInit函数的过程与Windows CE 6.0之前的版本完全不同,这是因为在Windows CE 6.0以前的版本中,由于内核(kernel)、OAL和KITL编译在一个可执行的文件中,它们之间的共享变量只需简单利用extern关键字申明便可相互之间进行访问,而在Windows CE 6.0中,由于内核(kernel)、OAL和KITL被编译成不同的可执行文件,变量之间的相互访问无法使用extern关键字实现共享,即内核无法使用extern DWORD varX方法访问OAL层的变量varX,当然OAL层的实现体同样无法通过同样的方式访问内核变量。为实现内核和OAL访问共享信息,Windows CE 6.0定义了OEMGLOBAL和GLOBAL两个结构体。 在 Windows CE 6.0的内核启动时,OS找到OAL的入口位置,然后调用入口函数与全局块进行指针交换,这样内核才能使用OAL层中的信息,同样OAL层才能访问内核(kernel)导出的函数。所以上述两个函数的调用实际上通过OEMGLOBAL结构体实现的。实际调用位置为$(_PRIVATEROOT)winceoscoreosnk oemstuboemstub.c中的OEMInitDebugSerial和OEMInit,这两个函数中通过OEMGLOBAL结构体指针访问 OAL层中的OEMInitDebugSerial和OEMInit。 调用KernelFindMemory()函数分割RAM区域,在Windows CE操作系统中,RAM空间主要分为存储内存和程序内存,存储内存主要为文件的存储空间,包括内核文件和复制到系统中所有目标文件,程序内存为运行程序时所需要的存储空间。KernelStart ()启动内核。$(_PRIVATEROOT)WINCEOSCOREOSNKKERNELARMmdarm.c void NKStartup (struct KDataStruct * pKData) PFN_OEMInitGlobals pfnInitGlob; PFN_DllMain pfnKitlEntry; DWORD dwCpuId = GetCpuId (); / (1) pickup arguments from the nk loader g_pKData = pKData; pTOC = (const ROMHDR *) pKData-dwTOCAddr; g_pOEMAddressTable = (PADDRMAP) pKData-pAddrMap; /* get architecture id and update page protection attributes */ pKData-dwArchitectureId = (dwCpuId 16) & 0xf; if (pKData-dwArchitectureId = ARMArchitectureV6) / v6 or later pKData-dwProtMask = PG_V6_PROTECTION; pKData-dwRead = PG_V6_PROT_READ; pKData-dwWrite = PG_V6_PROT_WRITE; pKData-dwKrwUro = PG_V6_PROT_URO_KRW; else / pre-v6 pKData-dwProtMask = PG_V4_PROTECTION; pKData-dwRead = PG_V4_PROT_READ; pKData-dwWrite = PG_V4_PROT_WRITE; pKData-dwKrwUro = PG_V4_PROT_URO_KRW; pKData-dwKrwUno = PG_V4_PROT_UNO_KRW;/ initialize nk globals FirstROM.pTOC = (ROMHDR *) pTOC; FirstROM.pNext = 0; ROMChain = &FirstROM; KInfoTableKINX_PTOC = (long)pTOC; KInfoTableKINX_PAGESIZE = VM_PAGE_SIZE; g_ppdirNK = (PPAGEDIRECTORY) &ArmHigh-firstPT0; pKData-pNk = g_pNKGlobal; / (2) find entry of oal pfnInitGlob = (PFN_OEMInitGlobals) pKData-dwOEMInitGlobalsAddr; / no checking here, if OAL entry point doesnt exist, we cant continue g_pOemGlobal = pfnInitGlob (g_pNKGlobal); g_pOemGlobal-dwMainMemoryEndAddress = pTOC-ulRAMEnd; pKData-pOem = g_pOemGlobal; / setup globals pVMProc = g_pprcNK; pActvProc = g_pprcNK; g_pNKGlobal-pfnWriteDebugString = g_pOemGlobal-pfnWriteDebugString; / (3) setup vectors, UC mappings, mode stacks, etc. ARMSetup (); / (4) common startup code. / try to load KITL if existif (pfnKitlEntry = (PFN_DllMain) g_pOemGlobal-pfnKITLGlobalInit) |(pfnKitlEntry = (PFN_DllMain) FindROMDllE
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年市场营销调研面试技巧数据收集与分析模拟题及解析
- 2025年物资储备仓库规划与建设知识测试题库及答案
- 电.钳工安全知识培训
- 2025年人力资源经理应聘考试题库及答案解析
- 神经外科医生的日常工作
- 甲状腺肿瘤护理课件
- 甲状腺炎课件
- 用药预防用药程序课件
- 江苏南京2020-2024年中考满分作文64篇
- 用电应急安全知识培训课件
- 人民医院心血管外科临床技术操作规范2023版
- 2023年江苏小高考历史试卷
- 主要组织相容性复合体及其编码分子
- 优化物理教学策略的思考(黄恕伯)
- 中国移动-安全-L1,2,3(珍藏版)
- 2017年全国大学生数学建模A题
- 2023年专升本计算机题库含答案专升本计算机真题
- scratch3.0编程校本课程
- GB/T 1685-2008硫化橡胶或热塑性橡胶在常温和高温下压缩应力松弛的测定
- GB/T 14825-1993农药可湿性粉剂悬浮率测定方法
- 固定资产清查工作报告
评论
0/150
提交评论