• 1、背景介绍 最近项目中需要做一个JTAG测试功能,该功能是需要在DDR的一段空间中准备一组数据,发送出去,再用DDR的另一段空间收数,判断收到的数是否和发送的...linux中提供了dev/mem来对DDR进行读写,让应用程...

    1、背景介绍

    最近项目中需要做一个JTAG测试功能,该功能是需要在DDR的一段空间中准备一组数据,发送出去,再用DDR的另一段空间收数,判断收到的数是否和发送的数据相同,以此加以验证。为此,需要在ZYNQ PL中实现GPIO通过HP读写DDR实地址的操作,同时在PS中通过ARM实现对发送和接收两段内存区域的读写操作。

    2、实现方法

    linux中提供了dev/mem来对DDR进行读写,让应用程序可以直接读写DDR实地址,很显然,这里也将采用这一方法。需要注意的是,在映射的过程中一定要加上O_SYNC标志位,这样才能保证Dcache和DDR中数据的一致性,确保读写时不光写入Dcache,也写入DDR中。

    代码如下:

    /*
     * Copyright (c) 2012 Xilinx, Inc.  All rights reserved.
     *
     * Xilinx, Inc.
     * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
     * COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
     * ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
     * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
     * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
     * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
     * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
     * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
     * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
     * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
     * AND FITNESS FOR A PARTICULAR PURPOSE.
     *
     */
    
    #include <stdio.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    //#include <asm/cacheflush.h>
    
    #include "gpio.h"
    
    void gpio_init()
    {
    	int temp;
    	int Delay;
    	SetGpioReg(GPIO_STATE_ADDR,0,0);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|jtx07_sbs;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|jtx07_tlr_trst;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|jtx07_tlr_trst6;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|jtag_oe_n;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	//set ddr send addr and recv addr
    	SetGpioReg(GPIO_ADDR,0,0x10000000);
    	SetGpioReg(GPIO_ADDR,8,0x20000000);
    
    	//set test data length
    	SetGpioReg(GPIO_WR_LEN_ADDR,0,sector_length);
    	SetGpioReg(GPIO_WR_LEN_ADDR,8,sector_length);
    
    	//set jtag test clk
    	SetGpioReg(GPIO_JTAG_SEL_ADDR,0,TCK_1_MHz);
    
    	//release reset signal
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|FPGA_RSTn;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|jtx07_reset;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	for (Delay = 0; Delay < 8000000; Delay++);
    
    	//enable jtag test
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|jtag_oe_n;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	for (Delay = 0; Delay < 8000000; Delay++);
    
    	//led trigger
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|LED0;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    }
    
    int main()
    {
    	int i;
    	int fd;
    	int temp;
    	int Delay;
    	int *start;
    	int *start_test;
    	int buf[1024*1024];
    
    	for(i=0;i<1024;i++)
    	{
    		buf[i]=i;
    	}
    #if 1
    	gpio_init();
    #endif
    	//open /dev/mem with read and write mode
    	fd = open ("/dev/mem", O_RDWR | O_SYNC);
    	if (fd < 0)
    	{
    		printf("cannot open /dev/mem.");
    		return -1;
    	}
    	//map physical memory 0-80M bytes
    	start = (int *)mmap(NULL, 0x400000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x10000000);
    	if(start < 0)
    	{
    		printf("mmap failed.");
    		return -1;
    	}
    	//write memory
    	memcpy(start, buf, 1024*1024);
    
    //	cacheflush(start,1024*4,DCACHE);
    
    //	flush_cache_all();
    #if 1
    	//Read value
    	for (i = 0;i <1024;i++)
    	{
    		printf("old mem[%d]:%x\n", i,*(start + i));
    	}
    #endif
    
    	munmap(start, 0x400000); //destroy map memory
    
    #if 1
    
    	printf("################################show new ddr################################\n");
    	start_test = (int *)mmap(NULL, 0x400000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x20000000);
    	if(start_test < 0)
    	{
    		printf("mmap failed.");
    		return -1;
    	}
    	for (i = 0;i <1024;i++)
    	{
    		printf("new mem[%d]:%x\n", i,*(start_test + i));
    	}
    	munmap(start_test, 0x400000); //destroy map memory
    
    	printf("################################before jtag start################################\n");
    #endif
    
    #if 1
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|sjtag_test_prepare;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	for (Delay = 0; Delay < 80000000; Delay++);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,8);
    	printf("JTAG STATE IS 0x%x\n",(temp & 0xFFF00000)>>20);
    
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|sjtag_test_start;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    	printf("JTAG TEST START\n");
    
    	for (Delay = 0; Delay < 80000000; Delay++);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,8);
    	printf("JTAG STATE IS 0x%x\n",(temp & 0xFFF00000)>>20);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp&~sjtag_test_start;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp&~FPGA_RSTn;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp&~sjtag_test_prepare;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,8);
    	printf("JTAG STATE IS 0x%x\n",(temp & 0xFFF00000)>>20);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,0);
    	temp=temp|FPGA_RSTn;
    	SetGpioReg(GPIO_STATE_ADDR,0,temp);
    
    	temp=GetGpioReg(GPIO_STATE_ADDR,8);
    	printf("JTAG STATE IS 0x%x\n",(temp & 0xFFF00000)>>20);
    #endif
    
    	printf("###########################after jtag start################################\n");
    	start = (int *)mmap(NULL, 0x400000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x20000000);
    	if(start < 0)
    	{
    		printf("mmap failed.");
    		return -1;
    	}
    	for (i = 0;i <1024;i++)
    	{
    		printf("new mem[%d]:%x\n", i,*(start + i));
    	}
    	munmap(start, 0x400000); //destroy map memory
    
    	close(fd); //close file
    	return 0;
    }
    

    上面代码中DDR发送区域物理起始地址为0x10000000,大小为0x400000

    接收区域物理起始地址为0x20000000,大小为0x400000。

    展开全文
  • 总的 DDR = OS+MMZ OS代表操作系统内存 MMZ为海思编解码等功能使用的内存 海思说明文档参考 1、DDR内存管理说明 1)所有DDR内存中,一部分由操作系统管理,称为OS内存;另一部分由MMZ模块管理,供媒体业务单独使用,...

    总的 DDR = OS+MMZ

    OS代表操作系统内存
    MMZ为海思编解码等功能使用的内存

    海思说明文档参考
    1、DDR内存管理说明
    1)所有DDR内存中,一部分由操作系统管理,称为OS内存;另一部分由MMZ模块管理,供媒体业务单独使用,称为MMZ内存。
    2)OS内存起始地址为0x40000000,内存大小可通过bootargs进行配置,例如第三章中的setenv bootargs 'mem=64M … ',表示分配给操作系统(OS)内存为64M,您可以根据实际情况进行调整。
    3)MMZ内存由MMZ内核模块管理(mpp/ko_hi35xx目录下的mmz.ko),加载mmz模块时,通过模块参数指定其起始地址及大小,load脚本中根据osmem大小来进行计算,例如:

      ./load3521d -a -ad 6134 -osmem 64
    

    您也可以通过修改mpp/ko目录下load3520dv400脚本中的mmz模块参数,来修改其起始地址和总大小。
    4)请注意MMZ内存地址范围不能与OS内存重叠。

    如果两者地址重合,出现ERROR,重新调整OS和mmz大小

    ERROR: Conflict MMZ:
    PHYS(0x90000000, 0x9FFFFFFF), GFP=0, nBYTES=262144KB,   NAME="anonymous"
    MMZ conflict to kernel memory (0x80000000, 0x9FFFFFFF)
    Add MMZ failed: PHYS(0x90000000, 0x9FFFFFFF), GFP=0, nBYTES=262144KB,   NAME="anonymous"
    

    OS内存使用情况查询

    cat  /proc/meminfo
    

    在这里插入图片描述

    MMZ内存使用查询:

    cat  /proc/media-mem 
    

    MMZ内存申请后不再增加,DDR内存在保证MMZ能够使用的情况下,OS多分配一些内存。
    红框中可以看到总分配的内存,已经使用和剩余的内存情况
    在这里插入图片描述

    展开全文
  • 转载:Linux内核中常见内存分配函数 1.原理说明 Linux内核中采用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系统中,用到了四级页表,如图2-1所示。四级页表...

    转载:Linux内核中常见内存分配函数

    1.   原理说明

    Linux内核中采用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系统中,用到了四级页表,如图2-1所示。四级页表分别为:

    l  页全局目录(Page Global Directory)

    l  页上级目录(Page Upper Directory)

    l  页中间目录(Page Middle Directory)

    l  页表(Page Table)

        页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址,每一个页表项指向一个页框。Linux中采用4KB大小的页框作为标准的内存分配单元。

    多级分页目录结构

    1.1.   伙伴系统算法

        在实际应用中,经常需要分配一组连续的页框,而频繁地申请和释放不同大小的连续页框,必然导致在已分配页框的内存块中分散了许多小块的空闲页框。这样,即使这些页框是空闲的,其他需要分配连续页框的应用也很难得到满足。

        为了避免出现这种情况,Linux内核中引入了伙伴系统算法(buddy system)。把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。

        假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块,如果没有,就去512个页框的链表中找,找到了则将页框块分为2个256个页框的块,一个分配给应用,另外一个移到256个页框的链表中。如果512个页框的链表中仍没有空闲块,继续向1024个页框的链表查找,如果仍然没有,则返回错误。

        页框块在释放时,会主动将两个连续的页框块合并为一个较大的页框块。

    1.2.   slab分配器

        slab分配器源于 Solaris 2.4 的分配算法,工作于物理内存页框分配器之上,管理特定大小对象的缓存,进行快速而高效的内存分配。

        slab分配器为每种使用的内核对象建立单独的缓冲区。Linux 内核已经采用了伙伴系统管理物理内存页框,因此 slab分配器直接工作于伙伴系统之上。每种缓冲区由多个 slab 组成,每个 slab就是一组连续的物理内存页框,被划分成了固定数目的对象。根据对象大小的不同,缺省情况下一个 slab 最多可以由 1024个页框构成。出于对齐等其它方面的要求,slab 中分配给对象的内存可能大于用户要求的对象实际大小,这会造成一定的内存浪费。

    2.    常用内存分配函数

    2.1.   __get_free_pages

        unsigned long __get_free_pages(gfp_tgfp_mask, unsigned int order)

     

        __get_free_pages函数是最原始的内存分配方式,直接从伙伴系统中获取原始页框,返回值为第一个页框的起始地址。__get_free_pages在实现上只是封装了alloc_pages函数,从代码分析,alloc_pages函数会分配长度为1<<order的连续页框块。order参数的最大值由include/linux/Mmzone.h文件中的MAX_ORDER宏决定,在默认的2.6.18内核版本中,该宏定义为10。也就是说在理论上__get_free_pages函数一次最多能申请1<<10 * 4KB也就是4MB的连续物理内存。但是在实际应用中,很可能因为不存在这么大量的连续空闲页框而导致分配失败。在测试中,order为10时分配成功,order为11则返回错误。

    2.2.   kmem_cache_alloc

        struct kmem_cache *kmem_cache_create(constchar *name, size_t size,

            size_talign, unsigned long flags,

            void(*ctor)(void*, struct kmem_cache *, unsigned long),

            void(*dtor)(void*, struct kmem_cache *, unsigned long))

        void *kmem_cache_alloc(struct kmem_cache *c,gfp_t flags)

     

        kmem_cache_create/ kmem_cache_alloc是基于slab分配器的一种内存分配方式,适用于反复分配释放同一大小内存块的场合。首先用kmem_cache_create创建一个高速缓存区域,然后用kmem_cache_alloc从该高速缓存区域中获取新的内存块。 kmem_cache_alloc一次能分配的最大内存由mm/slab.c文件中的MAX_OBJ_ORDER宏定义,在默认的2.6.18内核版本中,该宏定义为5,于是一次最多能申请1<<5 * 4KB也就是128KB的连续物理内存。分析内核源码发现,kmem_cache_create函数的size参数大于128KB时会调用BUG()。测试结果验证了分析结果,用kmem_cache_create分配超过128KB的内存时使内核崩溃。

    2.3.   kmalloc

        void *kmalloc(size_t size, gfp_t flags)

     

        kmalloc是内核中最常用的一种内存分配方式,它通过调用kmem_cache_alloc函数来实现。kmalloc一次最多能申请的内存大小由include/linux/Kmalloc_size.h的内容来决定,在默认的2.6.18内核版本中,kmalloc一次最多能申请大小为131702B也就是128KB字节的连续物理内存。测试结果表明,如果试图用kmalloc函数分配大于128KB的内存,编译不能通过。

    2.4.   vmalloc

        void *vmalloc(unsigned long size)

     

        前面几种内存分配方式都是物理连续的,能保证较低的平均访问时间。但是在某些场合中,对内存区的请求不是很频繁,较高的内存访问时间也可以接受,这是就可以分配一段线性连续,物理不连续的地址,带来的好处是一次可以分配较大块的内存。图3-1表示的是vmalloc分配的内存使用的地址范围。vmalloc对一次能分配的内存大小没有明确限制。出于性能考虑,应谨慎使用vmalloc函数。在测试过程中,最大能一次分配1GB的空间。

    Linux内核部分内存分布

    2.5.   dma_alloc_coherent

        void *dma_alloc_coherent(struct device *dev,size_t size,

    ma_addr_t*dma_handle, gfp_t gfp)

        DMA是一种硬件机制,允许外围设备和主存之间直接传输IO数据,而不需要CPU的参与,使用DMA机制能大幅提高与设备通信的吞吐量。DMA操作中,涉及到CPU高速缓存和对应的内存数据一致性的问题,必须保证两者的数据一致,在x86_64体系结构中,硬件已经很好的解决了这个问题,dma_alloc_coherent和__get_free_pages函数实现差别不大,前者实际是调用__alloc_pages函数来分配内存,因此一次分配内存的大小限制和后者一样。__get_free_pages分配的内存同样可以用于DMA操作。测试结果证明,dma_alloc_coherent函数一次能分配的最大内存也为4M。

    2.6.   ioremap

        void * ioremap (unsigned long offset,unsigned long size)

        ioremap是一种更直接的内存“分配”方式,使用时直接指定物理起始地址和需要分配内存的大小,然后将该段物理地址映射到内核地址空间。ioremap用到的物理地址空间都是事先确定的,和上面的几种内存分配方式并不太一样,并不是分配一段新的物理内存。ioremap多用于设备驱动,可以让CPU直接访问外部设备的IO空间。ioremap能映射的内存由原有的物理内存空间决定,所以没有进行测试。

    2.7.   Boot Memory

        如果要分配大量的连续物理内存,上述的分配函数都不能满足,就只能用比较特殊的方式,在Linux内核引导阶段来预留部分内存。

    2.7.1.      在内核引导时分配内存

        void* alloc_bootmem(unsigned long size)

        可以在Linux内核引导过程中绕过伙伴系统来分配大块内存。使用方法是在Linux内核引导时,调用mem_init函数之前用alloc_bootmem函数申请指定大小的内存。如果需要在其他地方调用这块内存,可以将alloc_bootmem返回的内存首地址通过EXPORT_SYMBOL导出,然后就可以使用这块内存了。这种内存分配方式的缺点是,申请内存的代码必须在链接到内核中的代码里才能使用,因此必须重新编译内核,而且内存管理系统看不到这部分内存,需要用户自行管理。测试结果表明,重新编译内核后重启,能够访问引导时分配的内存块。

    2.7.2.      通过内核引导参数预留顶部内存

        在Linux内核引导时,传入参数“mem=size”保留顶部的内存区间。比如系统有256MB内存,参数“mem=248M”会预留顶部的8MB内存,进入系统后可以调用ioremap(0xF800000,0x800000)来申请这段内存。

    3.    几种分配函数的比较

     

    分配原理

    最大内存

    其他

    __get_free_pages

    alloc_pages

    直接对页框进行操作,返回线性地址

    返回页地址

    4MB

    适用于分配较大量的连续物理内存

    kmem_cache_alloc

    基于slab机制实现

    128KB

    适合需要频繁申请释放相同大小内存块时使用

    kmalloc

    基于kmem_cache_alloc实现

    128KB

    最常见的分配方式,需要小于页框大小的内存时可以使用

    vmalloc

    建立非连续物理内存到虚拟地址的映射

     

    物理不连续,适合需要大内存,但是对地址连续性没有要求的场合

    dma_alloc_coherent

    基于__alloc_pages实现

    4MB

    适用于DMA操作

    ioremap

    实现已知物理地址到虚拟地址的映射

     

    适用于物理地址已知的场合,如设备驱动

    alloc_bootmem

    在启动kernel时,预留一段内存,内核看不见

     

    小于物理内存大小,内存管理要求较高

      注:表中提到的最大内存数据来自CentOS5.3 x86_64系统,其他系统和体系结构会有不同

     

    展开全文
  • Linux中可以将一部分内存mount为分区来使用,通常称之为RamDisk,分为:Ramdisk, ramfs, tmpfs. 1.Ramdisk 在编译内核时须将Device Drivers -->> Block devices -->> Ramdisk support 支持选上,它下面还有两个...

    在Linux中可以将一部分内存mount为分区来使用,通常称之为RamDisk,分为:Ramdisk, ramfs, tmpfs.

    1.Ramdisk

    在编译内核时须将Device Drivers -->> Block devices -->> Ramdisk support 支持选上,它下面还有两个选项:第一个设定Ramdisk个数,默认16个;第二个是设定Ramdisk的大小,默认是4096k。

    首先查看一下可用的RamDisk,使用ls /dev/ram*

    然后对/dev/ram0 创建文件系统,运行mke2fs /dev/ram0

    最后挂载 /dev/ram0,运行mount /dev/ram /mnt/test

    2.ramfs

    Ramfs顾名思义是内存文件系统,它处于虚拟文件系统(VFS)层,而不像ramdisk那样基于虚拟在内存中的其他文件系统(ex2fs)。

    因而,它无需格式化,可以创建多个,只要内存足够,在创建时可以指定其最大能使用的内存大小。

    在编译内核时须将File systems -->> pseudo filesystems -->>  Virtual memory file system support支持选上。

    # mount -t ramfs none /testRAM

    缺省情况下,Ramfs被限制最多可使用内存大小的一半。可以通过maxsize(以kbyte为单位)选项来改变。

    # mount -t ramfs none /testRAM -o maxsize=2000 (创建了一个限定最大使用内存为2M的ramdisk)

    3.Tmpfs

    是一个虚拟内存文件系统,它不同于传统的用块设备形式来实现的Ramdisk,也不同于针对物理内存的Ramfs。

    Tmpfs可以使用物理内存,也可以使用交换分区。在Linux内核中,虚拟内存资源由物理内存(RAM)和交换分区组成,这些资源是由内核中的虚拟内存子系统来负责分配和管理。

    Tmpfs向虚拟内存子系统请求页来存储文件,它同Linux的其它请求页的部分一样,不知道分配给自己的页是在内存中还是在交换分区中。同Ramfs一样,其大小也不是固定的,而是随着所需要的空间而动态的增减。

    在编译内核时须将File systems -->> pseudo filesystems -->>  Virtual memory file system support支持选上。

    # mkdir -p /mnt/tmpfs

    # mount tmpfs /mnt/tmpfs -t tmpfs

    同样可以在加载时指定tmpfs文件系统大小的最大限制:

    # mount tmpfs /mnt/tmpfs -t tmpfs -o size=32m 


    2,讲述Linux下使用RamDisk的方法和技巧


    先介绍一下什么是RamDisk。RamDisk实际是从内存中划出一部分作为一个分区使用,换句话说,就是把内存一部分当做硬盘使用,你可以向里边存文件。那么为什么要用RamDisk呢?假设有几个文件要频繁的使用,你如果将它们加到内存当中,程序运行速度会大副提高,因为内存的读写速度远高于硬盘。况且内存价格低廉,一台PC有128M或256M已不是什么新鲜事。划出部分内存提高整体性能不亚于更换新的CPU。何乐而不为呢?象WEB服务器这样的计算机,需要大量的读取和交换特定的文件,因此,在WEB服务器上建立RamDisk会大大提高网络读取速度。

    创建和使用RamDisk的方法。

    使用RamDisk非常方便,缺省安装的RedHat6.0就支持RamDisk。你所要作的就是格式化RamDisk并把它装载到一个目录下。要想查看RamDisk的数目,用命令"ls -al /dev/ram*",它会给出所有当前情况下可用的RamDisk。这些RamDisk只有使用的时候才占用内存。下面是使用RamDisk的几个命令:

    #创建装载点

    mkdir /tmp/ramdisk0

    # 创建一个文件系统

    mke2fs /dev/ram0

    #装载ramdisk:

    mount /dev/ram0 /tmp/ramdisk0

      这三个命令将会为RamDisk创建一个目录、格式化RamDisk(创建文件系统)并把RamDisk装载到目录"/tmp/ramdisk0"中。现在,你就可以把它作为一个磁盘分区使用了。

      如果格式化RamDisk失败,可能是因为你没有把对RamDisk的支持编译进内核中去。内核中对RamDisk的配置选项是 CONFIG_BLK_DEV_RAM。

      缺省的RamDisk为4M。使用mke2fs命令可以查知你所获RamDisk的大小。命令mke2fs /dev/ram0会产生以下信息:

    mke2fs 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09

    Linux ext2 filesystem format

    Filesystem label=

    1024 inodes, 4096 blocks

    204 blocks (4.98%) reserved for the super user

    First data block=1

    Block size=1024 (log=0)

    Fragment size=1024 (log=0)

    1 block group

    8192 blocks per group, 8192 fragments per group

    1024 inodes per group

    使用命令df /dev/ram0可以查到你实际能用的RamDisk的大小(文件系统也占用一定空间):

    >df -k /dev/ram0

    Filesystem 1k-blocks Used Available Use% Mounted on

    /dev/ram0 3963 13 3746 0% /tmp/ramdisk0

    不过要记住,RamDisk中的数据会在机器重新启动后消失,因此应把其中有用的数据及时备份到硬盘中。

    1. 改变RamDisk大小的技巧?

      为使用RamDisk,你或者要将对RamDisk的支持编译到内核中去,或者把它编译为一个可装载模块。编译为一个可装载模块有一个好处,就是可以在装载时任意指定RamDisk的大小。

      把下面这一行加到你的lilo.conf 文件中去:

    ramdisk_size=10000 (或对老内核写作ramdisk=10000)

      这样你键入LILO命令并重新启动后,缺省的RamDisk的大小将为10M,下面是我的/etc/lilo.conf文件:

    boot=/dev/hda

    map=/boot/map

    install=/boot/boot.b

    prompt

    timeout=50

    image=/boot/vmlinuz

    label=linux

    root=/dev/hda2

    read-only

    ramdisk_size=10000

    实际上,我只获得了9M多一点的RamDisk,其余被文件系统占用。

      当你编译为一个可装载模块后,你可以在模块装载时决定RamDisk的大小,这可以通过 /etc/conf中的选项设置来设定。或者通过作为ismod命令行参数来实现。

    options rd rd_size=10000

    insmod rd rd_size=10000

    下面是使用模块的例子:

    卸载下上一章装载的RamDisk, umount /tmp/ramdisk0.

    卸载模块rmmod rd。

    装载RamDisk模块并设置大小为20M,insmod rd rd_size=20000。

    创建文件系统,mke2fs /dev/ram0。

    装载RamDisk ,mke2fs /dev/ram0。

    在WEB服务器上使用RamDisk的实例?

      本例介绍在WEB服务器上使用3个RamDisk的方法。所用的WEB服务器是RedHat 6.0 自带的Apache。

      首先,把WEB根目录中所有文件移到其它目录中,然后创建RamDisk的装载点:

    mv /home/httpd/ /home/httpd_real

    mkdir /home/httpd

    mkdir /home/httpd/cgi-bin

    mkdir /home/httpd/html

    mkdir /home/httpd/icons

      然后,把以下命令加到你的/etc/rc.d/init.d/httpd.init文件中去:

    ### 创建3个RamDisk

    /sbin/mkfs -t ext2 /dev/ram0

    /sbin/mkfs -t ext2 /dev/ram1

    /sbin/mkfs -t ext2 /dev/ram2

    ### 加载RamDisk到开始创建的目录中

    mount /dev/ram0 /home/httpd/cgi-bin

    mount /dev/ram1 /home/httpd/icons

    mount /dev/ram2 /home/httpd/html

    ### 拷贝真正的目录中的所用文件到RamDisk 中

    tar -C /home/httpd_real -c . | tar -C /home/httpd -x

      最后,重新启动WEB服务器即可生效,试一下速度是否有所改变。

    后语:1. 一定要记住保存RamDisk中有用的东西,否则,重新启动后将化为乌有。你可以用cron设定一个计划,每隔10分钟扫描一下RamDisk中的文件是否发生变化,如有,拷贝到硬盘中,这会比较安全。

    2.最酷的应用是如果你有1G的内存,划出256M来作为暂存区/tmp,如果很多程序用到/tmp,那么你的系统性能会大大提高,而且重新启动后垃圾消失,真是一举两得。





    
    展开全文
  • 当PL端需要通过AXI总线访问DDR时,而PS端同样要访问到DDR,为了实现PL和PS对相同地址访问,可以通过定义变量到绝对地址的方法。 1. 单个变量 当只有一个变量情形下,可以定义一个指向DDR内存中的指针,比如: int...

    当PL端需要通过AXI总线访问DDR时,而PS端同样要访问到DDR,为了实现PL和PS对相同地址访问,可以通过定义变量到绝对地址的方法。
    1. 单个变量
    当只有一个变量情形下,可以定义一个指向DDR内存中的指针,比如:
    int* p=(int*)(0x100000);
    2. 数组
    对于数组不能用分配指针的方式来分配地址,这样在通过指针写或者读数据时,有可能同其它变量发生冲突。
    需要修改linker generator script来定义一个内存空间,将数组定义在这个空间中。http://sourceware.org/binutils/docs/ld/Scripts.html#Scripts
    (1)首先定义memory空间

    MEMORY
    {
       ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x100000, LENGTH = 0x1FF00000
       ps7_qspi_linear_0_S_AXI_BASEADDR : ORIGIN = 0xFC000000, LENGTH = 0x1000000
       ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x0, LENGTH = 0x30000
       ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00
       HEADMEM_BASEADDR : ORIGIN = 0x20000000, LENGTH = 0x00800000
       IMAGE1MEM_BASEADDR : ORIGIN = 0x20800000, LENGTH = 0x00200000
       IMAGE2MEM_BASEADDR : ORIGIN = 0x20A00000, LENGTH = 0x00200000
       KERNELMEM_BASEADDR : ORIGIN = 0x20C00000, LENGTH = 0x04000000
    }

    其中HEADMEM_BASEADDR ,IMAGE1MEM_BASEADDR ,IMAGE2MEM_BASEADDR ,KERNELMEM_BASEADDR 是我定义的。然后我们在这四个区间中定义section:

    SECTIONS{
    
    .headSection : {
       __headSection_start = .;
       *(.headSection)
       __headSection_end = .;   
    
    } > HEADMEM_BASEADDR
    
    .image1Section : {
       __image1Section_start = .;
       *(.image1Section)
       __image1Section_end = .;   
    
    } > IMAGE1MEM_BASEADDR
    
    
    .image2Section : {
       __image2Section_start = .;
       *(.image2Section)
       __image2Section_end = .;   
    
    } > IMAGE2MEM_BASEADDR
    
    
    .kernelSection : {
       __kernelSection_start = .;
       *(.kernelSection)
       __kernelSection_end = .;   
    
    } > KERNELMEM_BASEADDR
    
    }

    然后在C程序中通过attribute属性来定义数组到相应空间中,数组需要时全局变量。

    /*data.h*/
    extern u32 head_info[];
    extern u32 image1_info[];
    extern u32 image2_info[];
    extern u32 kernel_info[];
    /*data.c*/
    #include "data.h"
    u32 head_info[HEAD_SIZE] __attribute__((section(".headSection")));
    u32 image1_info[IMAGE_SIZE] __attribute__((section(".image1Section")));
    u32 image2_info[IMAGE_SIZE] __attribute__((section(".image2Section")));
    u32 kernel_info[KERNEL_SIZE] __attribute__((section(".kernelSection")));
    
    void data_init(){
    
        int k=0;
    
        for(int i=0;i<sizeof(head_info);i++){
            head_info[i]=k%1024;
            k++;
    
        }
    }
    /*main.c*/
    #include "data.c"
    int main(){
        data_init();
    
    }

    然后我们通过AXI总线访问DDR,在PL端可以读取到存储的数据。
    这里写图片描述

    展开全文
  • 首先分配基本变量(分配顺序字节从小到大char->int,除char按照singed->unsigned区分,其余均不),地址从低地址-高地址分配。 其次分配数组,地址从低地址-高地址。 一定要注意字节对齐:一般为4字节。 举例: ...
  • 不过Dma传输需要有一个前提条件,分配一段连续的物理内存,在linux下,由于存在虚实物理地址转换,用户访问的都是虚地址,分配一段连续的物理内存比较困难。常见的做法是在操作系统启动时预留一段物理内存专门用于...
  • mem为分配linux的可管理内存大小 setenv bootargs 'mem=42M 2、修改MPP加载时的osmem大小 osmem为配置linux内核内存大小。 ./load3518ev300 -i -sensor imx307_2l -osmem 42M -board demo 具体配置在load3518...
  • ZYNQ地址分配问题

    2019-07-29 17:17:53
    首先给出一篇很好的文章:Zynq构建SoC系统深度学习笔记-05-PL读写DDR3http://www.eefocus.com/antaur/blog/17-08/423773_0818c.html这个博主的...一、SoC地址空间分配(查看UG585)在UG585的第4章第1节给出了ZYNQ的地...
  • DDR3 初始化配置流程 系统上电之后,必须先完成DDR3 SDRAM 的初始化操作,系统才能访问DDR3 SDRAM。在进行初始化之前需要注意以下几点: 对DDR3 SDRAM 进行上电操作时,需要遵循JEDEC 标准。即先提供VDD,然 ...
  • http://www.wiki.xilinx.com/Zynq-7000+AP+SoC+-+32+Bit+DDR+Access+with+ECC+Tech+Tip http://patchwork.ozlabs.org/patch/441802/ http://blog.csdn.net/andy_wsj/article/details/9339247 ...
  • Linux的内存初始化

    2019-05-31 02:40:46
    看了很多关于linux内存管理的文章还是云里雾里,听了很多关于linux内存管理的课程还是一头雾水。其实很多时候造成不懂的原因不是资料太少,恰恰是资料太多,而且各个内核版...
  • DDR内存

    2009-07-29 18:10:00
    简称:DDR 标准:Double Date Rate 中文:双倍数据传输率 严格的说DDR应该叫DDR SDRAM,人们习惯称为DDRDDR SDRAM是Double Data RateSDRAM的缩写,是双倍速率同步动态随机存储器的意思。DDR内存是在SDRAM内存...
  • 在我们使用ARM等嵌入式Linux系统的时候,一个头疼的问题是GPU,Camera,HDMI等都需要预留大量连续内存,这部分内存平时不用, 但是一般的做法又必须先预留着。目前,Marek Szyprowski和Michal Nazarewicz实现了一套...
  • kernel version 2.6.29 内核函数常常需要临时分配一块任意大小的物理地址连续的内存空间. 所以先介绍内核中两个分配物理地址连续的内存空间的API.kmalloc由于采用了SLUB作为默认内存分配器, 所以 kmalloc 工作于 ...
  • 转载自:Linux 虚拟内存和物理内存的理解 虚拟内存: 第一层理解 1.、每个进程都有自己独立的4G内存空间,各个进程的内存空间具有类似的结构; 2、一个新进程建立的时候,将会建立起自己的内存空间,此进程的数据,...
  • uboot中对flash和ddr的管理 uboot阶段对flash的分区, uboot,var,kernel,rootfs,自由。 uboot中是没有操作系统中的,但是都有一个分区表决定分配方法, 这个分配不是随意的,比如soc要从第1个扇区开始读,我们...
  • 因此我们对Flash(相当于硬盘)的管理必须事先使用分区界定(实际上在uboot中和kernel中都有个分区表,分区表就是我们在做系统移植时对Flash的整体管理分配方法)。有了这个界定后,我们在部署系统时按照分区界定...
  • 9.1.uboot阶段Flash的分区 9.2.uboot阶段DDR的分区 9.3.shell是操作系统的终端命令行 9.4.shell是一类编程语言 9.5.常用的shell语言-sh、bash、csh、ksh、perl、python等 9.6.shell脚本的运行机制-解释运行
  • Linux 应用程序在被内核调入内存中运行后就成为一个进程,因此分析应用程序的地址空间实际上就是分析进程的地址空间分布。 应用程序的地址空间实际上由以下几个部分组成:代码段、初始化数据段、未初始化数据段(bss...
1 2 3 4 5 ... 20
收藏数 3,838
精华内容 1,535
热门标签