arm linux 传输文件
2018-03-14 18:19:57 u014671962 阅读数 397

#arm-cotex-A9 M6708 文件系统移植记录

本文的主要内容是:记录在移植文件系统时所遇到的问题。

##工具

* ubuntu 16.04.2 server i386(开启ssh、samba功能)
* buildroot-2017.02.3 (借助buildroot工具可以快速搭建文件系统)
* Qt-everywhere-opensource-src-5.6.2(此版本为企业长期服务版3年,且该版本不要求使用支持C++11的编译器)

##过程

  1. 解压buildroot-2017.02.3,并进入该目录。

  2. 安装软件:

    • sudo apt-get install libncurses5-dev(make menuconfig需要的包)
    • sudo apt-get install texinfo(makeinfo需要的包)
    • sudo apt-get install g++
    • 其他的根据提示安装
  3. make menuconfig(参考http://www.linuxdiyf.com/linux/22191.html)

    • 音频需要安装alsa库,环境变量添加:export ALSA_CONFIG_PATH=/usr/share/alsa/alsa.conf
    • 可以用buildroot安装tslib,环境变量如下(配置按实际情况修改):
      • export TSLIB_TSDEVICE=/dev/input/event0
      • export TSLIB_TSEVENTTYPE=input
      • export TSLIB_CONFFILE=/etc/ts.conf
      • export TSLIB_PLUGINDIR=/usr/lib/ts
      • export TSLIB_CALIBFILE=/etc/pointercal
      • export TSLIB_CONSOLEDEVICE=none
      • export TSLIB_FBDEVICE=/dev/fb0
    • 其他按实际需要选择安装
  4. make

    • buildroot的输出目录在buildroot-2017.02.3/output中,文件系统打包在image目录下
  5. 编译Qt5.6.2

    • 解压Qt源码
    • 修改qt-everywhere-opensource-src-5.6.2\qtbase\mkspecs\linux-arm-gnueabi-g++\qmake.conf
    • 使用buildroot的交叉编译链/home/cat/workspace/buildroot-2017.02.3/output/host/usr/bin/arm-none-linux-gnueabi-gcc
    • PATH="/home/cat/workspace/buildroot-2017.02.3/output/host/bin:/home/cat/workspace/buildroot-2017.02.3/output/host/sbin:/home/cat/workspace/buildroot-2017.02.3/output/host/usr/bin:/home/cat/workspace/buildroot-2017.02.3/output/host/usr/sbin:/home/cat/bin:/home/cat/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" PKG_CONFIG="/home/cat/workspace/buildroot-2017.02.3/output/host/usr/bin/pkg-config" PKG_CONFIG_LIBDIR="/home/cat/workspace/buildroot-2017.02.3/output/host/usr/arm-buildroot-linux-gnueabi/sysroot/usr/lib/pkgconfig" PKG_CONFIG_SYSROOT_DIR="/home/cat/workspace/buildroot-2017.02.3/output/host/usr/arm-buildroot-linux-gnueabi/sysroot" MAKEFLAGS=" --no-print-directory – -j5" …/qt-everywhere-opensource-src-5.6.2/configure -nomake tests -confirm-license -release -opensource -xplatform linux-arm-gnueabi-g++ -prefix /home/cat/workspace/tools/armQt5.6.2 -qt-sql-sqlite -qt-zlib -qt-libpng -qt-libjpeg -nomake tests -nomake examples -nomake tools -no-opengl -alsa -glib -pulseaudio
    • PATH="/home/cat/workspace/buildroot-2017.05.2/output/host/bin:/home/cat/workspace/buildroot-2017.05.2/output/host/sbin:/home/cat/workspace/buildroot-2017.05.2/output/host/usr/bin:/home/cat/workspace/buildroot-2017.05.2/output/host/usr/sbin:/home/cat/workspace/buildroot-2017.05.2/output/host/bin:/home/cat/workspace/buildroot-2017.05.2/output/host/sbin:/home/cat/workspace/buildroot-2017.05.2/output/host/usrbin:/home/cat/workspace/buildroot-2017.05.2/output/host/usr/sbin:/home/cat/bin:/home/cat/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/snap/bin"
    • PKG_CONFIG="/home/cat/workspace/buildroot-2017.05.2/output/host/usr/bin/pkg-config"
    • PKG_CONFIG_LIBDIR="/home/cat/workspace/buildroot-2017.05.2/output/host/usr/arm-buildroot-linux-gnueabi/sysroot/usr/lib/pkgconfig"
    • PKG_CONFIG_SYSROOT_DIR="/home/cat/workspace/buildroot-2017.05.2/output/host/usr/arm-buildroot-linux-gnueabi/sysroot"
    • …/qt-everywhere-opensource-src-5.9.1/configure -nomake tests -confirm-license -release -opensource -xplatform linux-arm-gnueabi-g++ -prefix /home/cat/workspace/tools/armQt5.9.1 -qt-sqlite -qt-zlib -qt-libpng -qt-libjpeg -nomake tests -nomake examples -nomake tools -no-opengl -alsa -glib -pulseaudio -skip serialbus
    • 路径按实际情况修改
    • make -j4
    • make install
  6. 将编译好的Qt库(lib文件夹)和插件(plugins文件夹)复制到文件系统中。

    • 编译好的Qt的bin目录下需要新增一个qt.conf文件,内容如下:
    • [Paths]
    • Prefix=…
  7. 添加Qt环境变量

    • export QT_QPA_FB_TSLIB=1
    • export QT_QPA_GENERIC_PLUGINS=tslib
    • export QT_QPA_PLATFORM=LinuxFb:fb=$TSLIB_FBDEVICE
    • export QT_QPA_PLATFORM_PLUGIN_PATH=/usr/plugins
    • export QT_QPA_FONTDIR=/usr/lib/fonts
    • export QML_IMPORT_PATH=/usr/qml
    • export QML2_IMPORT_PATH=/usr/qml
2010-10-30 19:50:00 RichardYSteven 阅读数 788

还有一篇讲到怎么编译zImage的,也挺牛的

http://blog.csdn.net/pottichu/archive/2009/06/11/4261150.aspx

 

 

http://blog.csdn.net/arriod/archive/2008/08/21/2808861.aspx

 

这是 ARM-Linux 运行的第一个文件,这些代码是一个比较独立的代码包裹器。其作用就是解压 Linux 内核,并将 PC 指针跳到内核( vmlinux )的第一条指令。

Bootloader 中传入到 Linux 中的参数总共有三个, Linux 中用到的是第二个和第三个。第二个参数是 architecture id ,第三个是 taglist 的地址。 Architecture id arm 芯片在 Linux 中一定要唯一。 Taglist bootload Linux 传入的参数列表(详细的解释请参考《 booting arm linux.pdf 》)。

// 程序的入口点

              .section ".start", #alloc, #execinstr

/*

  * sort out different calling conventions

  */

              .align

start:

              .type       start,#function

              .rept       8 // 重复 8 次下面的指令,也就是空出中断向量表的位置

              mov r0, r0 // 就是 nop 指令

              .endr

 

              b     1f

              .word       0x016f2818              @ Magic numbers to help the loader

              .word       start               @ absolute load/run zImage address

              .word       _edata                   @ zImage end address

1:            mov r7, r1                  @ save architecture ID

              mov r8, r2                  @ save atags pointer

 

#ifndef __ARM_ARCH_2__

              /*

                * Booting from Angel - need to enter SVC mode and disable

                * FIQs/IRQs (numeric definitions from angel arm.h source).

                * We only do this if we were in user mode on entry.

                */

              mrs r2, cpsr        @ get current mode

              tst   r2, #3                  @ not user?

              bne       not_angel

              mov r0, #0x17            @ angel_SWIreason_EnterSVC

              swi       0x123456              @ angel_SWI_ARM

not_angel:

              mrs r2, cpsr        @ turn off interrupts to

              orr  r2, r2, #0xc0              @ prevent angel from running

              msr       cpsr_c, r2

#else

              teqp       pc, #0x0c000003         @ turn off interrupts

#endif

 

一定要保证当前运行在 SVC 模式下,否则会跳到 swi 里面去(为什么?我不清楚,而且我没有处理过这个 swi )。然后再关闭 irq fiq

 

              /*

                * Note that some cache flushing and other stuff may

                * be needed here - is there an Angel SWI call for this?

                */

 

              /*

                * some architecture specific code can be inserted

                * by the linker here, but it should preserve r7, r8, and r9.

                */

 

读入地址表。因为我们的代码可以在任何地址执行,也就是位置无关代码( PIC ),所以我们需要加上一个偏移量。下面有每一个列表项的具体意义。

GOT 表的初值是连接器指定的,当时程序并不知道代码在哪个地址执行。如果当前运行的地址已经和表上的地址不一样,还要修正 GOT 表。

              .text

              adr  r0, LC0

              ldmia       r0, {r1, r2, r3, r4, r5, r6, ip, sp}

              subs r0, r0, r1             @ calculate the delta offset

 

                                          @ if delta is zero, we are

              beq       not_relocated           @ running at the address we

                                          @ were linked at.

 

              /*

                * We're running at a different address.  We need to fix

                * up various pointers:

                *   r5 - zImage base address

                *   r6 - GOT start

                *   ip - GOT end

                */

              add r5, r5, r0

              add r6, r6, r0

              add  ip, ip, r0

 

              /*

                * If we're running fully PIC === CONFIG_ZBOOT_ROM = n,

                * we need to fix up pointers into the BSS region.

                *   r2 - BSS start

                *   r3 - BSS end

                *   sp - stack pointer

                */

              add r2, r2, r0

              add r3, r3, r0

              add       sp, sp, r0

 

修改 GOT (全局偏移表)表。根据当前的运行地址,修正该表。

              /*

                * Relocate all entries in the GOT table.

                */

1:            ldr  r1, [r6, #0]          @ relocate entries in the GOT

              add r1, r1, r0             @ table.  This fixes up the

              str  r1, [r6], #4          @ C references.

              cmp r6, ip

              blo       1b

 

BSS 段,所有的 arm 程序都需要做这些的。

 

not_relocated:       mov r0, #0

1:            str  r0, [r2], #4          @ clear bss

              str  r0, [r2], #4

              str  r0, [r2], #4

              str  r0, [r2], #4

              cmp r2, r3

              blo       1b

 

正如下面的注释所说, C 环境我们已经设置好了。下面我们要打开 cache mmu 。为什么要这样做呢?这只是一个解压程序呀?为了速度。那为什么要开 mmu 呢,而且只是做一个平板式的映射?还是为了速度。如果不开 mmu 的话,就只能打开 icache 。因为不开 mmu 的话就无法实现内存管理,而 io 区是决不能开 dcache 的。

 

              /*

                * The C runtime environment should now be setup

                * sufficiently.  Turn the cache on, set up some

                * pointers, and start decompressing.

                */

              bl       cache_on

是不是要跟读进去呢?对于只是对流程感兴趣的人只是知道打开 cache 就行了。不过跟进去是很有乐趣的,这就是为什么虽然 Linux 如此庞大,但仍有人会孜孜不倦的研究它的每一行代码的原因吧。反过来说,对于 Linux 内核的整体把握更加重要,要不然就成盲人摸象了。还有,想做 ARM 高手的人可以读 Linux 下的每一个汇编文件,因为 Linux 内核用 ARM 的东西还是比较全的。

 

              mov r1, sp                  @ malloc space above stack

              add r2, sp, #0x10000       @ 64k max

 

对下面这些地址的理解其实还是很麻烦,但有篇文档写得很清楚《 About TEXTADDR, ZTEXTADDR, PAGE_OFFSET etc... 》。下面程序的意义就是保证解压地址和当前程序的地址不重叠。上面分配了 64KB 的空间来做解压时的数据缓存。

/*

  * Check to see if we will overwrite ourselves.

  *   r4 = final kernel address // 内核执行的最终实地址

  *   r5 = start of this image // 该程序的首地址

  *   r2 = end of malloc space (and therefore this image)

  * We basically want:

  *   r4 >= r2 -> OK

  *   r4 + image length <= r5 -> OK

  */

              cmp r4, r2

              bhs       wont_overwrite

              add r0, r4, #4096*1024       @ 4MB largest kernel size

              cmp r0, r5

              bls       wont_overwrite

 

如果空间不够了,只好解压到缓冲区地址后面。调用 decompress_kernel 进行解压缩,这段代码是用 c 实现的,和架构无关。

 

              mov r5, r2                  @ decompress after malloc space

              mov r0, r5

              mov r3, r7

              bl       decompress_kernel

 

完成了解压缩之后,由于空间不够,内核也没有解压到正确的地址,必须通过代码搬移来搬到指定的地址。搬运过程中有可能会覆盖掉现在运行的这段代码,所以必须将有可能会执行到的代码搬运到安全的地方,这里用的是解压缩了的代码的后面。

 

              add r0, r0, #127

              bic  r0, r0, #127         @ align the kernel length

/*

  * r0     = decompressed kernel length

  * r1-r3  = unused

  * r4     = kernel execution address

  * r5     = decompressed kernel start

  * r6     = processor ID

  * r7     = architecture ID

  * r8     = atags pointer

  * r9-r14 = corrupted

  */

              add r1, r5, r0             @ end of decompressed kernel

              adr  r2, reloc_start

              ldr  r3, LC1

              add r3, r2, r3

1:            ldmia       r2!, {r9 - r14}        @ copy relocation code

              stmia       r1!, {r9 - r14}

              ldmia       r2!, {r9 - r14}

              stmia       r1!, {r9 - r14}

              cmp r2, r3

              blo       1b

 

              bl       cache_clean_flush // 因为有代码搬移,所以必须先清理( clean )清除( flush cache

              add       pc, r5, r0        @ call relocation code

 

decompress_kernel 共有 4 个参数,解压的内核地址、缓存区首地址、缓存区尾地址、和芯片 ID ,返回解压缩代码的长度。

 

/*

  * We're not in danger of overwriting ourselves.  Do this the simple way.

  *

  * r4     = kernel execution address

  * r7     = architecture ID

  */

wont_overwrite:       mov r0, r4

              mov r3, r7

              bl       decompress_kernel

              b       call_kernel

 

针对于不会出现代码覆盖的情况,就简单了。直接解压缩内核并且跳转到首地址运行。 call_kernel 这个函数我们会在下面分析它。

 

              .type       LC0, #object

LC0:              .word       LC0               @ r1

              .word       __bss_start              @ r2

              .word       _end                     @ r3

              .word       zreladdr          @ r4

              .word       _start                    @ r5

              .word       _got_start              @ r6

              .word       _got_end        @ ip

              .word       user_stack+4096            @ sp

LC1:              .word       reloc_end - reloc_start

              .size       LC0, . - LC0

 

上面这个就是刚才我们说过的地址表,里面有几个符号的地址定义。 LC0 是在这里定义的。 Zreladdr 是在当前目录下的 Makfile 里定义的。其他的符号是在 lds 里定义的。

 

下面我们来分析一下有关 cache mmu 的代码。通过这些代码我们可以看到 Linux 的高手们是如何通过汇编来实现各个 ARM 处理器的识别,以达到通用的目的。

/*

  * Turn on the cache.  We need to setup some page tables so that we

  * can have both the I and D caches on.

  *

  * We place the page tables 16k down from the kernel execution address,

  * and we hope that nothing else is using it.  If we're using it, we

  * will go pop!

  *

  * On entry,

  *  r4 = kernel execution address

  *  r6 = processor ID

  *  r7 = architecture number

  *  r8 = atags pointer

  *  r9 = run-time address of "start"  (???)

  * On exit,

  *  r1, r2, r3, r9, r10, r12 corrupted

  * This routine must preserve:

  *  r4, r5, r6, r7, r8

  */

              .align       5

cache_on:       mov r3, #8                     @ cache_on function

              b       call_cache_fn

 

这里涉及到了很多 MMU cache writebuffer TLB 的操作和协处理器的编程。具体编程的东西,我就不想多说了,可以对这 ARM 的手册逐行的理解。至于为什么要这样做,熟悉了他们的工作原理后也就不难理解了(《 ARM 嵌入式系统开发》这本书就有个比较好的说明)。因为这里包含了太多的代码搬运、解压等费时的操作,所以打开 cache 是有必要的。由于要用到数据 cache 所以需要对 mmu 进行配置。为了简单这里制作了一级映射,而且是物理地址和虚拟地址相同的 1:1 映射。

 

__setup_mmu:       sub  r3, r4, #16384           @ Page directory size

              bic  r3, r3, #0xff        @ Align the pointer

              bic  r3, r3, #0x3f00

/*

  * Initialise the page tables, turning on the cacheable and bufferable

  * bits for the RAM area only.

  */

              mov r0, r3

              mov r9, r0, lsr #18

              mov r9, r9, lsl #18              @ start of RAM

              add       r10, r9, #0x10000000       @ a reasonable RAM size

              mov r1, #0x12

              orr  r1, r1, #3 << 10

              add r2, r3, #16384

1:            cmp r1, r9                  @ if virt > start of RAM

              orrhs       r1, r1, #0x0c            @ set cacheable, bufferable

              cmp r1, r10                @ if virt > end of RAM

              bichs       r1, r1, #0x0c            @ clear cacheable, bufferable

              str  r1, [r0], #4          @ 1:1 mapping

              add r1, r1, #1048576

              teq  r0, r2

              bne       1b

 

参考下面的注释,如果当前在 flash 中运行,我们再映射 2MB 。就算是当前在 RAM 中执行其实也没关系,只不过是做了重复工作。

 

/*

  * If ever we are running from Flash, then we surely want the cache

  * to be enabled also for our execution instance...  We map 2MB of it

  * so there is no map overlap problem for up to 1 MB compressed kernel.

  * If the execution is in RAM then we would only be duplicating the above.

  */

              mov r1, #0x1e

              orr  r1, r1, #3 << 10

              mov r2, pc, lsr #20

              orr  r1, r1, r2, lsl #20

              add r0, r3, r2, lsl #2

              str  r1, [r0], #4

              add r1, r1, #1048576

              str  r1, [r0]

              mov       pc, lr

 

__armv4_cache_on:

              mov       r12, lr

              bl       __setup_mmu

              mov r0, #0

              mcr       p15, 0, r0, c7, c10, 4       @ drain write buffer

              mcr       p15, 0, r0, c8, c7, 0 @ flush I,D TLBs

              mrc       p15, 0, r0, c1, c0, 0 @ read control reg

              orr  r0, r0, #0x5000           @ I-cache enable, RR cache replacement

              orr  r0, r0, #0x0030

              bl       __common_cache_on

              mov r0, #0

              mcr       p15, 0, r0, c8, c7, 0 @ flush I,D TLBs

              mov       pc, r12

 

__common_cache_on:

#ifndef DEBUG

              orr  r0, r0, #0x000d           @ Write buffer, mmu

#endif

              mov r1, #-1

              mcr       p15, 0, r3, c2, c0, 0 @ load page table pointer

              mcr       p15, 0, r1, c3, c0, 0 @ load domain access control

              mcr       p15, 0, r0, c1, c0, 0 @ load control register

              mov       pc, lr

 

/*

  * All code following this line is relocatable.  It is relocated by

  * the above code to the end of the decompressed kernel image and

  * executed there.  During this time, we have no stacks.

  *

  * r0     = decompressed kernel length

  * r1-r3  = unused

  * r4     = kernel execution address

  * r5     = decompressed kernel start

  * r6     = processor ID

  * r7     = architecture ID

  * r8     = atags pointer

  * r9-r14 = corrupted

  */

 

下面这段代码是在解压空间不够的情况下需要重新定位的,具体原因上面已经说明。

 

              .align       5

reloc_start:       add  r9, r5, r0

              debug_reloc_start

              mov r1, r4

1:

              .rept 4

              ldmia       r5!, {r0, r2, r3, r10 - r14}       @ relocate kernel

              stmia       r1!, {r0, r2, r3, r10 - r14}

              .endr

 

              cmp r5, r9

              blo       1b

              debug_reloc_end

 

这是最后一个函数了,这个时候一切实质性的工作已经做完。关闭 cache ,并跳转到真正的内核入口。

 

call_kernel:     bl       cache_clean_flush

              bl       cache_off

              mov r0, #0                  @ must be zero

              mov r1, r7                  @ restore architecture number

              mov r2, r8                  @ restore atags pointer

              mov       pc, r4                    @ call kernel

 

/*

  * Here follow the relocatable cache support functions for the

  * various processors.  This is a generic hook for locating an

  * entry and jumping to an instruction at the specified offset

  * from the start of the block.  Please note this is all position

  * independent code.

  *

  *  r1  = corrupted

  *  r2  = corrupted

  *  r3  = block offset

  *  r6  = corrupted

  *  r12 = corrupted

  */

 

通过下面函数我们可以通过 proc_types 结构体数组我们可以顺利的找到现在的处理器型号,并且会根据 R3 的偏移量跳转到相应的函数中。里面涉及到协处理器 CP15 c0 的操作,如果有疑问,可以参考 ARM 相关手册。

 

call_cache_fn:       adr   r12, proc_types

              mrc       p15, 0, r6, c0, c0     @ get processor ID

1:            ldr  r1, [r12, #0]        @ get value

              ldr  r2, [r12, #4]        @ get mask

              eor  r1, r1, r6             @ (real ^ match)

              tst   r1, r2                  @       & mask

              addeq       pc, r12, r3              @ call cache function

              add       r12, r12, #4*5

              b       1b

 

/*

  * Table for cache operations.  This is basically:

  *   - CPU ID match

  *   - CPU ID mask

  *   - 'cache on' method instruction

  *   - 'cache off' method instruction

  *   - 'cache flush' method instruction

  *

  * We match an entry using: ((real_id ^ match) & mask) == 0

  *

  * Writethrough caches generally only need 'on' and 'off'

  * methods.  Writeback caches _must_ have the flush method

  * defined.

  */

              .type       proc_types,#object

proc_types:

              .word       0x41560600            @ ARM6/610

              .word       0xffffffe0

              b       __arm6_cache_off   @ works, but slow

              b       __arm6_cache_off

              mov       pc, lr

@           b       __arm6_cache_on           @ untested

@           b       __arm6_cache_off

@           b       __armv3_cache_flush

 

              .word       0x00000000            @ old ARM ID

              .word       0x0000f000

              mov       pc, lr

              mov       pc, lr

              mov       pc, lr

 

              .word       0x41007000            @ ARM7/710

              .word       0xfff8fe00

              b       __arm7_cache_off

              b       __arm7_cache_off

              mov       pc, lr

 

              .word       0x41807200            @ ARM720T (writethrough)

              .word       0xffffff00

              b       __armv4_cache_on

              b       __armv4_cache_off

              mov       pc, lr

 

              .word       0x00007000            @ ARM7 IDs

              .word       0x0000f000

              mov       pc, lr

              mov       pc, lr

              mov       pc, lr

 

              @ Everything from here on will be the new ID system.

 

              .word       0x4401a100            @ sa110 / sa1100

              .word       0xffffffe0

              b       __armv4_cache_on

              b       __armv4_cache_off

              b       __armv4_cache_flush

 

              .word       0x6901b110            @ sa1110

              .word       0xfffffff0

              b       __armv4_cache_on

              b       __armv4_cache_off

              b       __armv4_cache_flush

 

              @ These match on the architecture ID

 

              .word       0x00020000            @ ARMv4T

              .word       0x000f0000

              b       __armv4_cache_on

              b       __armv4_cache_off

              b       __armv4_cache_flush

 

              .word       0x00050000            @ ARMv5TE

              .word       0x000f0000

              b       __armv4_cache_on

              b       __armv4_cache_off

              b       __armv4_cache_flush

 

              .word       0x00060000            @ ARMv5TEJ

              .word       0x000f0000

              b       __armv4_cache_on

              b       __armv4_cache_off

              b       __armv4_cache_flush

 

              .word       0x00070000            @ ARMv6

              .word       0x000f0000

              b       __armv4_cache_on

              b       __armv4_cache_off

              b       __armv6_cache_flush

 

              .word       0                   @ unrecognised type

              .word       0

              mov       pc, lr

              mov       pc, lr

              mov       pc, lr

 

              .size       proc_types, . - proc_types

 

/*

  * Turn off the Cache and MMU.  ARMv3 does not support

  * reading the control register, but ARMv4 does.

  *

  * On entry,  r6 = processor ID

  * On exit,   r0, r1, r2, r3, r12 corrupted

  * This routine must preserve: r4, r6, r7

  */

              .align       5

cache_off:       mov r3, #12                     @ cache_off function

              b       call_cache_fn

 

// 代码略

 

这里分配了 4K 的空间用来做堆栈。

 

reloc_end:

 

              .align

              .section ".stack", "w"

user_stack:       .space       4096

2017-11-25 10:39:13 SYB773849846 阅读数 977

以读写方式mount NTFS文件系统

Mount NTFS文件系统让他具有读写访问的权限有点复杂。这涉及到其它软件的安装,例如fuse和ntfs-3g。在这两种情况下你可能需要使用软件包管理器,例如:yum、apt-get,synaptic等,并且安装它到你的标准发行版硬盘上。检查软件包ntfs-3g和fuse。

3.1.  安装其它软件

3.1.1.   Fuse安装

http://fuse.sourceforge.net上下载源代码 # wget http://easynews.dl.sourceforge.net/sourceforge/fuse/fuse-2.7.1.tar.gz 解压缩源代码: # tar zxf fuse-2.7.1.tar.gz 编译和安装fuse源代码 # cd fuse-2.7.1 # ./configure --exec-prefix=/; make; make install

3.1.2.   Ntfs-3g安装

从网站http://www.tuxera.com/community/ntfs-3g-download/上下载源代码包: http://tuxera.com/opensource/ntfs-3g_ntfsprogs-2011.4.12.tgz 解压缩安装: # tar zxf ntfs-3g_ntfsprogs-2011.4.12.tgz 编译和安装ntfs-3g源代码。 # cd ntfs-3g_ntfsprogs-2011.4.12 # ./configure # make # make install

3.2.  Mount NTFS分区

如果在安装过程中没有出现错误,NTFS卷可以mount到Linux上,并且具有读写权限。 # fdisk -l | grep NTFS # mount -t ntfs-3g /dev/sdb1 /mnt/ntfs [root@localhost ntfs-3g_ntfsprogs-2011.4.12]# mount -t ntfs-3g /dev/sdb1 /mnt/ntfs FATAL: Module fuse not found.  (这是由于没有安装fuse模块导致的) 下载网址:http://ftp.riken.go.jp/Linux/cern/slc52test/extras/x86_64/failed/ 在google上查找kernel-module-fuse-2.6.18-128.el5PAE的rpm安装程序,下载安装然后重新mount。
2009-05-30 14:49:00 songok2007 阅读数 885

基于ARM Linux的图像采集与蓝牙传输

嵌入式Linux系统具有可移植性好、网络功能强、优秀的GNU编译工具、免费的开放源代码等优点。S3C2410处理器是一款采用ARM920T结构,内部资源非常丰富的32位嵌入式处理器。USB摄像头具有低廉的价格,良好的性能,加上Linux下有V4L支持对其编程,很容易集成到嵌入式系统中。蓝牙技术是目前被认可的短距离无线通信技术,广泛应用于手机、电脑以及汽车免提系统。

  本文介绍基于嵌入式Linux的USB图像采集系统,并通过构建好的嵌入式Linux下的蓝牙环境将采集到的图片传送到蓝牙手机上,实现监控功能。

  1 软硬件平台概述

  系统硬件平台如图1所示。该平台软件上采用嵌入式Linux操作系统;硬件上采用Samsung公司的S3C2410处理器,另外配置了64 MB的NAND Flash存储器和64MB的SDRAM,通过以太网控制芯片CS8900扩展一个10M以太网接口。引出两个USB主口,一个接USB摄像头,一个接USB蓝牙适配器;将通过USB摄像头采集到的图像数据输出到缓冲区中,保存成文件,并通过蓝牙传输到蓝牙手机上。

[img]http://www.dzsc.com/data/uploadfile/20079269416492.jpg[/img]

  2 摄像头驱动

  在Linu
x下已经支持的摄像头驱动是采用OV511芯片的摄像头。使用这款芯片的摄像头有网眼2000/3000等系列,而现在市面上常见的摄像头芯片大多采用中芯微的zc0301、zc0302和zc0303等。Linux内核中并没有相关的驱动支持,但可以从网上下载到相关的spca5xx驱动。

  本系统就采用市面上最常用的zc0301p1芯片的摄像头。由于是用于ARM开发板上,可以下载专用于嵌入式Linux的spca5xx-LE驱动,LE版的驱动最大限度地减少了内存的使用,符合嵌入式的需要。将下载的驱动加入到内核中,修改Makefile和Kconfig文件,在内核中选中USB_SPCA5XX,编译后就将摄像头的驱动加入到内核映像中了。

  3 Video4Linux简介

  Video4Linux(简称“V4L”)是Linux下用于获取视频和音频数据的API接口,配合适当的视频采集设备和相应的驱动程序,可以实现影像/图片采集、AM/FM广播、频道切换等功能,在远程会议、可视电话、视频监控系统中都有广泛的应用。

  在Linux下,所有外设都被看成是一种特殊文件,称为“设备文件”,可以像访问普通文件一样对其进行读写。一般来说,采用V4L驱动的摄像头设备文件是/dev/v4l/video0。为了通用,可建立一个到/dev/video0的连接。

  V4L支持两种方式来捕获图像:mmap(内存映射方式)和read(直接读取方式)。

  V4L在include/linux/videodev.h文件中定义了一些重要的数据结构,在进行图像的采集过程中,就是通过对这些数据的操作来获得最终的图像数据。

  4 图像采集

  在图像采集过程中,采用V4L的read方式直接读取设备来获取JPEG格式的图像数据,具体流程如图2所示。
[img]http://www.dzsc.com/data/uploadfile/20079269416527.jpg[/img]


  4.1 初始化摄像头设备

  指定要操作的摄像头设备文件/dev/video0,调用OPEN()打开该设备文件,将自定义的数据结构vdIn中的成员初始化,包括设备名称(vd->videodevice)、要采集图像的宽度(vd->hdrwidth)和高度(vd->hdrheight)、像素位数(vd->bppIn)、帧大小(vd->framesizeIn),为帧数据分配存储空间(vd->pFramebuffer)。

 

  4.2 设定待采集图像的各种属性

  zc0301p1摄像头支持JPEG格式的图像采集,定义VIDEO_PALETTE_JPEG为21,将其赋值给图像帧的调色板palette,这是一个必须设置的重要的参数。其他参数(如图像色调、颜色、对比度等)可以先将VIDIOCGPICT传递给ioctl()查看其默认值。

 

  如果发觉以上的参数不符合采集图像的规范,则可以将pict.brightness、pict.colour、pict.contrast、pict.white-ness、pict.depth等重新赋值,再将VIDIOCSPICT传递给ioctl()来重新设置这些参数。

 

  4.3 进行图像采集

  在图像采集过程中,采用read方法直接读取设备文件来获取一帧数据保存到缓冲区中,通过convertframe()函数将pFramebuffer中的数据转成完整的JPEG格式的数据保存到ptframe缓存中去,再调用fwrite()函数将pt-frame缓存中的JPEG格式数据写入到指定的文件中去,即得到一幅JPEG格式的图像。

5 蓝牙传输

  蓝牙协议规范遵循开放系统互连参考模型(OPENSystem Interconnection/Referenced Model,OSI/RM),从低到高地定义了蓝牙协议堆栈的各个层次。

 


  在蓝牙协议体系中,OBEX位于RFCOMM之上。OBEX提供了对象的表示模型,并通过“Put”和“Get”操作传输对象。设备间的对话遵循客户和服务器间的请求—响应模式。OBEX会话开始由客户端发出连接请求,连接建立成功后服务器发送成功的连接响应,否则发送连接不成功的连接响应。在连接之后,客户端可以通过Put请求向服务器“推送(Push)”对象,如果对象较大,Put请求可以使用多个Put请求分组,每个请求分组需返回一个Put响应分组。本系统将采集到的图片保存到/tmp/cap.jpeg,现在要将图片通过蓝牙传输到蓝牙手机上。具体实现过程如下:

  ① 在内核中打上蓝牙补丁,加入蓝牙协议的支持,添加USB蓝牙适配器的驱动。

  ② 编译bluez的库和工具。从网上下载bluez-libs、bluez-utils和dbus库,用ARM-Linux-gcc完成交叉编译,得到了arm版的bl
uez库和bluez的工具以及dbus-daemon工具。这是蓝牙适配器在ARM Linux的环境下正常工作所必需的。

  ③ 启动USB蓝牙适配器。要使USB蓝牙适配器正常工作,需要用到步骤②中编译得到的dbus-daemon工具和一些蓝牙工具(如hciconfig、hcid等)。dbus是一个消息传递系统,应用程序间可通过它来相互传递消息。dbus-daemon是一个守护进程,是运行hcid所必需的,hcid用来读入hcid.conf文件。该文件是蓝牙设备的一个配置文件,在该配置文件中设置好蓝牙设备的类型、classid、配对码、设备是否可被搜索等其他的属性。

  ④ 实现文件传输。本系统采用OBEX协议的客户/服务器模式来传递采集到的图片文件,需要用到蓝牙的Object PUSH服务。首先用sdptool工具搜索到蓝牙手机的MAC地址以及Object PUSH服务所占用的频道,然后用rfcomm工具将该频道绑定到虚拟串口,最后运行obex_test完成文件的传输。
采用Object PUSH服务来实现文件传输的流程。

 

  结 语

  本设计实现了ARM Linux环境下的图像采集工作,构建了ARM Linux下的蓝牙工作环境;通过蓝牙的OBEX协议和Object PUSH服务,实现了ARM Linux平台与蓝牙手机之间的文件传输。利用嵌入式系统和无线传输实现远程监控,符合数字化、网络化的发展趋势。

2013-08-23 11:46:00 weixin_30787531 阅读数 5

在arm开发的过程中,要将Linux下开发的程序传输到arm中,试了一下串口,没搞通,听同时说nfs,就google了一下,下面记录一下使用过程,引用了eten的csdn博客。

出处:http://blog.csdn.net/leo115/article/details/7340682

1.  安装 NFS 相关组件

sudo apt-get install nfs-kernel-server


安装完nfs服务器之后,我们需要建立一个与下位机挂接的共享文件夹。

2.  建立NFS共享文件夹

sudo mkdir -R /mnt/nfs


3.设置共享目录
修改主机 /etc/exports 文件,添加如下代码

/mnt/nfs  *(rw,sync,no_root_squash)

这里做一下说明:
/mnt/nfs 表示所设定的共享文件,这里可以任意改,
* 表示任意网段的下位机都可以连接到此文件夹

(rw,sync,no_root_squash) //表示一些权限

rw                           可读写的权限
ro                           只读的权限

no_root_squash     NFS 客户端分享目录使用者的权限,即如果客户端使用的是 root 用户,那么对于这个共享的目录而言,该客户端就具有 root 的权限,若是以NFS挂载根文件系统时,必须设置此项 sync                       资料同步写入到内存与硬盘当中
async                     资料会先暂存于内存当中,而非直接写入硬盘


设置完共享文件夹之后需要重启NFS 服务器,


 

4.   服务操作指令

 

#重启
$sudo /etc/init.d/portmap restart
# 停止
sudo /etc/init.d/nfs-kernel-server stop
# 启动
sudo /etc/init.d/nfs-kernel-server start
# 重新启动
sudo /etc/init.d/nfs-kernel-server restart


这些做好之后我们可以在自己PC机上做一下测试

5.  测试

首先,我们可以使用如下命令查看所建立的共享文件夹

showmount -e

如果看到显示:

Export list for ubuntu:
/mnt/nfs *

则表示主机设置成功。

注意:

  1.完成后如出现 access denied 异常,重新启动系统即可

  2.在 ubuntu 11.10 中启动 nfs 服务时会遇到

     * Not starting: portmapper is not running

解决方法:

sudo service portmap restart
sudo /etc/init.d/nfs-kernel-server start


接下来,我们来设置ARM开发板上的一些信息。

 

要想ARM开发板和PC机能够建立网络文件共享,必须将ARM开发板与PC 通过网线连接起来,并且设置ARM开发板和PC 机在同一网段
我们可以通过如下命令来查看和修改ARM开发板IP地址:

ifconfig     //查看以太网开 IP 地址 ,主机同样是这个命令

ifconfig eth0 192.168.1.1    //这个命令是修改以太网卡 IP 地址,这里我的PC机的IP 地址是 
                              192.168.1.104,要修改为同一网段


这样修改过之后,目标板和PC机在linux下能够互相很快地ping通。

6.  ARM开发板和PC机挂接

使用如下命令挂接

mount -t nfs -o nolock 192.168.1.104:/mnt/nfs /mnt/nfs

说明:
这里192.168.1.104是我的PC 机的IP地址,
第一个/mnt/nfs是我在PC 机上设置的NFS共享文件夹目录
第二个/mnt/nfs是我在ARM开发板上设置的共享文件夹目录

这条命令执行过之后就实现了ARM开发板和PC机之间的NFS网络文件系统挂接。

使用时,在将要传输的文件复制到PC机的/mnt/nfs目录下,在arm板的/mnt/nfs目录下就可以看到相应的文件,然后使用cp命令拷贝到自己的工作目录就可以了。

转载于:https://www.cnblogs.com/rogge/p/3277202.html

没有更多推荐了,返回首页