王灵芝课件第十次课bootloader_第1页
王灵芝课件第十次课bootloader_第2页
王灵芝课件第十次课bootloader_第3页
王灵芝课件第十次课bootloader_第4页
王灵芝课件第十次课bootloader_第5页
已阅读5页,还剩76页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第5章 bootloader 漳州师范学院王灵芝本章主要内容5.1 嵌入式系统的引导代码5.2 Bootloader之ViVi5.4FS2410的BootLoader5.1 嵌入式系统的引导代码本节内容1、Bootloader简介2、Bootloader工作模式 3、Bootloader启动过程建立交叉编译环境Bootloader的/移植/配置/编译kernel的移植/配置/编译根文件系统Cramfs的实现嵌入式系统软件开发流程用户应用程序开发5.1.1 Bootloader简介Bootloader,为引导加载程序,是嵌入式系统加电后运行的第一段代码,相当于PC机的BIOS。 Bootload

2、er的位置:通常固化在硬件上的某个固态存储设备上,加电后自启动。 Bootloader功能:初始化硬件设备、建立内存空间的映射图,将系统的软、硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。 Bootloader在软件的层次位置Bootloader的地址:在嵌入式系统中,系统在上电或复位时从地址0 x0000,0000处开始执行,在这个地址处安排的就是Bootloader。Bootloader是严重地依赖于硬件而实现的。每种不同体系结构的处理器都有不同的Bootloader。不过Bootloader的发展也趋于支持多种体系结构,如现在比较成熟的vivi、RedBoot和

3、U-Boot等。 几种发布的Bootloader1、vivivivi是韩国Mizi公司开发的Bootloader,适用于ARM9处理器。2、RedBoot RedBoot即红帽(Red Hat)嵌入式调试引导程序,是一种用于嵌入式系统的独立开放源代码引导/装载器。3、U-Boot U-Boot(Universal Bootloader)由德国DENX小组开发,是一款目前功能较为强大的开源Bootloader程序,它支持多种处理器平台,包括ARM、PowerPC、MIPS等。 5.1.2 Bootloader操作模式 大多数Bootloader都有两种不同的操作模式:“启动加载”模式和“下载”模

4、式。其区别对于开发人员才有意义。从最终用户的角度看,Bootloader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载模式的区别。 1、启动加载(Bootloading)模式启动加载模式称为“自举”(Autonomous)模式。即Bootloader从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。启动加载模式是 Bootloader的正常工作模式,在嵌入式产品发布的时侯,Bootloader必须工作在这种模式下。 2、下载(Downloading)模式下载方式:在这种模式下,目标机上的Bootloader将通过串口连接或网络连接等通信手

5、段从主机下载文件。下载内容及存储:主要是下载内核映像和根文件系统映像等。从主机下载的文件通常首先被Bootloader保存到目标机的RAM中,然后再被 Bootloader写到目标机上的FLASH 类固态存储设备中。下载模式应用场合:Bootloader的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用到这种工作模式。用户应用接口:工作于这种模式下的Bootloader通常都会向它的终端用户提供一个简单的命令行接口。 如在RedBoot下,将出现“RedBoot”提示符;在vivi Bootloader 下出现“vivi”提示符。2、下载(Downloading)

6、模式2、下载(Downloading)模式RedBoot的Bootloader像RedBoot或U-Boot等功能强大的Bootloader通常都可同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。比如,RedBoot在启动时处于正常的启动加载模式,但是它会延时3秒等待终端用户按下任意键而将RedBoot切换到下载模式。如在等待时间内没有接收到用户按键,则继续启动 Linux 内核。 5.1.3 Bootloader启动过程Bootloader的启动可以分为两个阶段 p1461、第一阶段阶段1主要包含依赖于CPU体系结构及硬件设备的初始化等。通常都用汇编语言来实现。这个阶段的任

7、务有5:(1)、基本的硬件设备初始化这是 Bootloader 一开始就执行的操作,其目的是为阶段2 的执行、以及随后kernel 的执行准备好一些基本的硬件环境。 它通常包括以下工作:1 屏蔽所有的中断。为中断提供服务通常是 OS 设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断。2 设置 CPU 的速度和时钟频率。 3 RAM 初始化。包括正确地设置系统的内存控制器的功能寄存器以及各内存控制寄存器等。 4 初始化 LED。典型地,通过 GPIO 来驱动 LED,其目的是表明系统的状态是 OK 还是 Error。如果板子上没有 LED,那么也可以通过初始

8、化 UART 向串口打印 Boot Loader 的 Logo 字符信息来完成这一点。 5 关闭 CPU 内部指令数据 cache。通常使用cache以及写缓存是为了提高系统性能,但是可能该改变访问主存的数量、类型和时间,因此Boot Loader 不需要5.1.3 Bootloader启动过程(2)、为阶段2代码准备RAM空间为了获得更快的执行速度,通常把 阶段2 的代码加载到 RAM 空间中来执行。 准备RAM空间考虑的因素:阶段2代码大小、堆栈、页大小(4KB的倍数)、安排位置等。 总的空间有1MB足够,安排在RAM的顶端较恰当。(3)、拷贝阶段2代码到RAM空间(4)、设置好堆栈堆栈指

9、针sp设置在1MB 的 RAM 空间的最顶端(堆栈向下生长)。(5)、跳转到阶段2的C程序入口点在上述一切都就绪后,就可以跳转到 Bootloader 的 stage2 去执行了。2、第二阶段阶段2通常用C语言来实现,以便实现更复杂的功能,也使程序有更好的可读性和可移植性。这个阶段的主要任务有5个:(1)、初始化本阶段要使用到的硬件至少初始化一个串口,以便和终端用户进行 I/O 输出信息等。(2)、检测系统内存映射(memory map)所谓内存映射,就是指明在整个物理地址空间中有哪些地址范围被分配用来作为系统的 RAM 单元。为后面使用RAM、运行程序做好准备。(3)、将kernel和根文件

10、系统映像从flash读到RAM空间(4)、为kernel设置启动参数这是在调用内核之前应该做的准备工作。Linux 2.4.x 以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。启动参数标记列表方法:以ATAG_CORE标记开始,以ATAG_NONE标记结束。在嵌入式 Linux 系统中,通常需要由 Boot Loader 设置的启动参数有:ATAG_CORE、ATAG_MEM(内存映射)、ATAG_NONE等。(5)、调用内核Bootloader调用Linux kernel的方法是直接跳转到内核的第一条指令处。在跳转时必须满足下列条件:1)、CPU寄存器的设置:R0为

11、0;R1为机器类型ID;R2为启动参数,标记列表在RAM中的起始基地址。 (机器类型参见 linux/arch/arm/tools/mach-types目录)2)、CPU模式: CPU必须设置为SVC模式,必须禁止中断(IRQs和FIQs)。3)、 MMU 和 Cache的设置:MMU 必须关闭;指令 Cache 可以打开也可以关闭; 数据 Cache 必须关闭。5.1 vivi Bootloader接口命令vivi有两种工作模式,一种是 “启动加载”模式,另一种是命令行模式。利用串行口与主机的连接,可以进行命令行操作。vivi启动后,通过串行口发出如下信息:Press Return to s

12、tart the Linux now, any other key for vivi按下除了“Enter”之外的键,便可进入命令行模式。vivi的接口命令有5条。vivi接口命令命 令功 能Load下载flash或RAM命令PartMTD分区操作命令param设置、查看参数命令Boot启动系统命令flashFlash管理命令1、load下载文件命令功能:将二进制文件下载到Flash或RAM格式:load | media_type:存储器类型,Flash或RAMpartname:分区名称addr size:下载的地址及占用空间大小x|y|z:文件的传输协议。x表示采用xmodem协议,y表示采用

13、ymodem协议,z表示采用zmodem协议。目前vivi仅支持xmodem协议。例1:viviload flash kernel x表示下载压缩的内核映像文件zImage到flash存储器的内核分区中,采用xmodem传输协议。例2:viviload flash 0 x80000 0 xc0000 x2、partMTD分区操作命令操作命令:显示、增加、删除、复位、保存MTD分区等。各个命令格式:part show:显示分区信息part del :删除指定的分区part reset:恢复分区的默认值part save:在flash中保存分区和参数值增加新的分区part add :partnam

14、e:新分区名称offset:新分区的偏移地址size:新分区的大小flag:新分区的类型,可以是JFFS2、LOCKED、BONFS3、param设置或查看分区参数命令查看分区参数: param show设置启动等待按键延迟:param set boot_delay n(s)设置通信初始化超时:param set xmodem_initial_timeout m (s)4、boot引导内核命令格式:boot media_type | media_type:存储器类型,flash或RAMpartname:内核所在分区名称addr:内核所在器件的偏移地址size:内核的大小若boot(无参数),则

15、从kernel内核对应的分区(kernel)读取内核映像启动。例如:1、viviboot nand 0 x80000内核在nand flash中,偏移地址为0 x80000,大小为缺省值0 xc00002、viviboot nor 0 x80000例如:vivi bootvivi 从kernel mtd 分区处读到linux 内核文件。有时,要在ram 中验证内核,所以,可用如下命令vivi load ram 0 x30008000 0 xd0000 xvivi boot ramvivi 就从ram 中启动linux 内核。5、flashflash存储器管理命令擦除flash数据格式:flas

16、h erase | 说明:对flash只有擦除命令。例如:flash erase 0 x80000 0 xc0000一、对vivi进行配置运行vivi配置程序menuconfig: makemenuconfig启动对vivi配置的主菜单,根据自己的目标系统逐项进行设置,设置完后退出保存即可。5.2.2 vivi源码的修改移植vivi的移植方法步骤:对vivi进行修改移植对vivi进行配置对vivi进行编译下载、运行vivi二、对vivi进行修改移植设Linux系统的目录结构为设Linux系统的目录结构为:cygwinfriendly-arm crosstool kernel vivi1、修改v

17、ivi/Makefile(1)修改交叉编译库和头文件 1)修改编译器路径:将: PILE=/opt/host/armv4l/bin/armv4l-unknown-linux-修改为: PILE= arm-linux-gcc的路径如: PILE=/friendly-arm/ crosstool/arm-linux/gcc-2.95.3-glibc-2.2.3/bin/arm-linux-2)修改编译器库文件路径:将:ARM_GCC_LIBS=/opt/host/armv4l/bin/gcc-lib/armv4l-unknown-linux/2.95.2修改为: ARM_GCC_LIBS=符合本机

18、的路径如:ARM_GCC_LIBS= /friendly-arm/ crosstool/arm-linux/gcc-2.95.3-glibc-2.2.3/lib/gcc-lib/arm-linux/2.95.3 3)增加交叉编译时头文件的搜索路径:LIBC_INCLUDE_DIR=本机的include的路径如:LIBC_INCLUDE_DIR= /friendly-arm/ crosstool/arm-linux/gcc-2.95.3-glibc-2.2.3/include(2)Linux内核包含文件 修改Linux头文件所在路径将:LINUX_INCLUDE_DIR=/opt/host/ar

19、mv4l/include改为:LINUX_INCLUDE_DIR=符合本机的如:LINUX_INCLUDE_DIR=/friendly-arm/kernel/include2、修改vivi中与硬件相关的部分只需要修改:/friendly-arm/vivi/include/platform/下面的文件smdk2410.h即可。文件smdk2410.h的内容是针对开发板的硬件配置的,主要有:时钟设置、存储器初始化、通用I/O口初始化、UART初始化、vivi初始配置等。根据自己的目标板的实际情况进行设置即可。 3、支持Nor Flash启动的修改 (vivi/arch/s3c2410/smdk.c

20、)(1) Nor flash分区对于一个嵌入式系统,可能会采用Nor flash、Nand flash、SDRAM等多种介质构成存储器系统, Nor flash(如1、2MB)用于存放、运行bootloader,Nand flash用于存放操作系统、其它系统软件、应用程序和各种文件, SDRAM用于运行程序和存放数据。如果系统有Nor flash存储器(一般没有),则需要做相应修改。修改方法:在vivi/arch/s3c2410/smdk.c中的分区代码,添加上Nor flash分区:#ifdef CONFIG_S3C2410_AMD_BOOTmtd_partition_t default_m

21、td_partitions = name:vivi,offset:0,size:0 x00020000,flag:0, name:param,offset:0 x00020000,size:0 x00010000,flag:0, name:kernel,offset:0 x00030000,size:0 x000C0000,flag:0, name:root,offset:0 x00100000,size:0 x00140000,flag:MF_BONFS;#endif(2)内核启动参数设置经过上面修改,系统板可以从Nand flash中启动Linux,也可以从Nor flash中启动Linu

22、x,另外还需要修改启动命令:#ifdef CONFIG_S3C2410_NAND_BOOTChar Linux_cmd = noinitrd root=/dev/bon/2 init =/linuxrc console=tty1console=ttyS0;#elseChar Linux_cmd = noinitrd root=/dev/mtdblock/3init =/linuxrc console=tty1 console=ttyS0;式中启动命令:noinitrd:不使用ramdisk;root:根文件系统所在的MTD分区init:内核运行入口命令文件console:内核信息输出控制台tt

23、yS0表示串行口;tty0表示虚拟终端LCD。说明:关于Linux启动命令的参数,可以参考Kernel/Documentatio/下面的文件kernel-parameters.txt。4、增加一种下载操作load flash j操作在Nand启动时,可以从JTAG下载程序到SDRAM(0 x30000000),然后用“load flashj”来烧写相应的分区,并且可以做vivi、kernel、root这3个分区的操作。其中大部分操作与使用X-Modem和 Y-Modem等功能类似,所以命名为J-Modem,并特别修改以下3个部分。(1)在 vivi/include/priv_data.h中增加

24、宏定义原来为:#define X_MODEM1#define Y_MODEM2#define Z_MODEM3增加:#define JTAG_D4(2)在 vivi/lib/load_file.c中增加对J-Modem的识别原来为:modem_is(const char *mt) else if (strncmp(z, mt, 1) = 0) return Z_MODEM; else return UNKNOWN_MODEM;修改为:modem_is(const char *mt) else if (strncmp(z, mt, 1) = 0) return Z_MODEM; else if

25、(strncmp(“J, mt, 1) = 0) return JTAG_D; else return UNKNOWN_MODEM;说明:该修改仅提高了下载到SDRAM的速度三、对vivi进行编译在vivi目录下执行以下命令: makecleanmake make clean是清除以前编译时生成的所有目标文件和临时文件。如果没有错误,编译后会生成vivi的目标文件vivi.bin。四、对vivi进行下载利用JTAG口将vivi下载到目标板的Nor flash空间(0 x000000 x20000)。然后对目标板加电,使vivi启动运行,观察运行情况。一、vivi源代码目录结构vivi源代码包含

26、的目录有:arch、Documentation、drivers、init、include、lib、scripts、test、util等10目录,共300多个文件。各个目录内容如下:1、arch(architecture)目录它下面的文件为与CPU硬件相关的初始化代码,此目录包含了所用vivi支持的CPU。一般只包含S3C2410 x的文件。第一阶段程序的入口点2、Documentation目录其下文件为vivi使用指南。3、drivers目录存放的为MTD(数据存储媒质)设备读写控制文件和串行口操作文件,对串行口支持xmodem和ymodem协议。4、init目录该目录下是系统初始化文件mai

27、n.c、version.c,后者是vivi版本信息,main.c为vivi整个初始化的结构。3、drivers目录第二阶段程序的入口点5、init目录5、lib目录该目录下是公共应用及接口代码,如时钟功能文件time.c,堆栈初始化文件heap.c等文件。 6、include目录存放所有的头文件,包括S3C2410微处理器的和S3C2410开发板的头文件。7、scripts目录该目录存放的是系统配置需要的脚本文件,如menuconfig和configue文件。 8、CVS目录所有的目录下面都有一个CVS目录,存放的是该目录的路径和它的子目录。lib目录include目录在lib/platfor

28、m/smdk2410.h中定义了与开发板相关的资源配置参数,我们往往只需要修改这个文件就可以配置目标板的参数比如时钟、波特率、引导参数、物理内存映射等5、lib目录该目录下是公共应用及接口代码,如时钟功能文件time.c,堆栈初始化文件heap.c等文件。 6、include目录存放所有的头文件,包括S3C2410微处理器的和S3C2410开发板的头文件。7、scripts目录该目录存放的是系统配置需要的脚本文件,如menuconfig和configue文件。 8、CVS目录所有的目录下面都有一个CVS目录,存放的是该目录的路径和它的子目录。scripts目录该目录存放的是系统配置需要的脚本文

29、件,如menuconfig和configue文件。CVS目录 所有的目录下面都有一个CVS目录,存放的是该目录的路径和它的子目录。二、vivi源代码文件与功能结构vivi源代码文件:1、vivi/arch/s3c2410/head.s2、一段过度,实现循环调用,main返回后重新复位LDRSP,DW_STACK_STARTMOVFP,#0MOVA2,#0BLmainMOVPC,#FLASH_BASE3、vivi/init/main.c在汇编中利用跳转语句跳入main()函数。当main()函数返回时,重启(1)阶段1:arch/s3c2410/head.Shead.S有900多行,沿着代码执行

30、的顺序,head.S完成9件事情.下面我们会详细的介绍.当执行完head.S的代码后,内存的使用情况如下:映射到bank6开始的存储器单元.地址从0 x300000000-0 x34000000共64M的存储空间将VIVI的第一阶段拷贝到bank0地址为0 x000000000开始的4K字节,作为起步石为加载 stage2 准备 RAM 空间1M为加载 stage2 准备 RAM 空间 为了获得更快的执行速度,通常把 stage2 加载到 RAM 空间中来执行,因此必须为加载 Boot Loader 的 stage2 准备好一段可用的 RAM 空间范围。 由于 stage2 通常是 C 语言执

31、行代码,因此在考虑空间大小时,除了 stage2 可执行映象的大小外,还必须把堆栈空间也考虑进来。此外,空间大小最好是 memory page 大小(通常是 4KB)的倍数。一般而言,1M 的 RAM 空间已经足够了。具体的地址范围可以任意安排,比如 将 stage2 安排到整个 RAM 空间的最顶 1MB(也即(RamEnd-1MB) - RamEnd)是一种值得推荐的方法。 (1)阶段1:arch/s3c2410/head.S 沿着代码执行的顺序,head.S完成如下几件事情: 1、关WATCH DOG:上电后,WATCH DOG默认是开着的 p1512、禁止所有中断:vivi中没用到中断

32、(不过这段代码实在多余,上电后中断默认是关闭的) p1523、初始化系统时钟:启动MPLL,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改为“Asynchronous bus mode”。请参考实验:时钟与总线 4、初始化内存控制寄存器:还记得那13个寄存器吗?请复习实验五:SDRAM控制器5、检查是否从掉电模式唤醒,若是,则调用WakeupStart函数进行处理这是一段没用上的代码,vivi不可能进入掉电模式 (1)阶段1:arch/s3c2410/head.S6、点亮所有LED p1537、初始化UART0: p154a设置GPIO,选

33、择UART0使用的引脚 b初始化UART0,设置工作方式(不使用FIFO)、波特率115200 8N1、无流控等,请参考实验:UART 8、将vivi所有代码(包括阶段1和阶段2)从nand flash复制到SDRAM中: P155-156 请参考实验:FLASH控制器a设置nand flash控制寄存器 P155reset NANDb设置堆栈指针调用C函数时必须先设置堆栈 P156get read to call C functionc设置即将调用的函数nand_read_ll的参数:r0=目的地址(SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度(以字节为单

34、位) P156copy vivi to RAMd调用nand_read_ll进行复制 e进行一些检查工作:上电后nand flash最开始的4K代码被自动复制到一个称为“Steppingstone”的内部RAM中(地址为0 x00000000-0 x00001000);在执行nand_read_ll之后,这4K代码同样被复制到SDRAM中(地址为0 x33f00000-0 x33f01000)。比较这两处的4K代码,如果不同则表示出错 copy vivi to RAM ldr r0, =VIVI_RAM_BASE ;SRAM存放vivi的基地址 /*在/vivi/linux/platform/

35、smdk2410.h中定义 #define VIVI_RAM_BASE (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE) #define VIVI_RAM_SIZESZ_1M*/ mov r1, #0 x0 /nand flash中放置的VIVI首地址mov r2, #0 x20000 ;0 x20000-128k字节 /拷贝的数据块大小,可以修改的bl nand_read_ll ;nand_read_ll在/vivi/arch/s3c2410/nand_read.c中定义 ;r0,r1,r2分别为函数的三个参数 ;从NANDFlash的0地址拷贝128k到SDR

36、AM指定处 VIVI_RAM_BASE tst r0, #0 x0 beq ok_nand_read 若读取正确,跳转到ok_nand_read#ifdef CONFIG_DEBUG_LL 否则打印错误信息bad_nand_read: ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord 1: b 1b infinite loop #endif ok_nand_read: 打印正确信息#ifdef CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord #endif 8、将vivi所有代码(包

37、括阶段1和阶段2)从nand flash复制到SDRAM中: P155-156 请参考实验:FLASH控制器a设置nand flash控制寄存器 P155reset NANDb设置堆栈指针调用C函数时必须先设置堆栈 P156get read to call C functionc设置即将调用的函数nand_read_ll的参数:r0=目的地址(SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度(以字节为单位) P156copy vivi to RAMd调用nand_read_ll进行复制 e进行一些检查工作:上电后nand flash最开始的4K代码被自动复制到一

38、个称为“Steppingstone”的内部RAM中(地址为0 x00000000-0 x00001000);在执行nand_read_ll之后,这4K代码同样被复制到SDRAM中(地址为0 x33f00000-0 x33f01000)。比较这两处的4K代码,如果不同则表示出错 void nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) int i, j; if (start_addr & NAND_BLOCK_MASK) | (size & NAND_BLOCK_MASK) return ; /* 若为无效

39、参数,退出 invalid alignment */ NFCONF &= 0 x800; /* chip Enable */ for(i=0; i 10; i+); for(i=start_addr; i 9) & 0 xff; NFADDR = (i 17) & 0 xff; NFADDR = (i 25) & 0 xff; wait_idle(); /等待系统空闲/从FLASH地址中读入数据存入SRAM中指定的地址,完成将vivi复制到RAM for(j=0; j NAND_SECTOR_SIZE; j+, i+) *buf = (NFDATA & 0 xff); buf+; /* chi

40、p Disable */ NFCONF |= 0 x800; /* chip disable */ return ; inline void wait_idle(void) int i;while(!(NFSTAT & BUSY)for(i=0; i10; i+); /这段的作用是判断NAND的状态, NFSTAT=0/表明NAND忙,执行延时子程序。等待NAND空闲9、跳到bootloader的阶段2运行就是调用init/main.c中的main函数: a重新设置堆栈 b设置main函数的参数 c调用main函数P155get read to C function LDRSP,DW_STACK_STARTMOVFP,#0MOVA2,#0BLmainMOVPC,#FLASH_BASE2、第二阶段阶段2通常用C语言来实现,以便实现更复杂的功能,也使程序有更好的可读性和可移植性。这个阶段的主要任务有5个:(1)、初始化本阶段要使用到的硬件(2)、检测系统内存映射(memory map)所谓内存映射,就是指明在整个物理地址空间中有哪些地址范围被分配用来作为系统的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论