当前位置: 首页 > wzjs >正文

经典网站设计企业管理系统的功能

经典网站设计,企业管理系统的功能,建设银行的网站是多少钱,企业网站开发教程1 概述 本文主要介绍在Linux中如何预留出一块内存,以及预留内存的原理与使用方式,只停留在应用阶段,因为涉及Linux内存管理,没有深入Linux对预留管理的基础原理和源码,留待后续Linux内存管理章节分析。读者若只想了解如…

1 概述

        本文主要介绍在Linux中如何预留出一块内存,以及预留内存的原理与使用方式,只停留在应用阶段,因为涉及Linux内存管理,没有深入Linux对预留管理的基础原理和源码,留待后续Linux内存管理章节分析。读者若只想了解如何在Linux下预留内存的应用,本文比较合适。

        本文验证环境使用qemu模拟vpress平台做的,关于该环境的搭建,参考笔者之前写的文章:

使用qemu搭建armv7嵌入式开发环境_qemu armv7-CSDN博客

2 Linux下的CMA

2.1 CMA

        Linux内核的连续内存分配器 (CMA),Contiguous Memory Allocator,是内存管理子系统中的一个模块,负责物理地址连续的内存分配。CMA的核心并不是设计精巧的算法来管理地址连续的内存块,实际上它的底层还是依赖内核伙伴系统这样的内存管理机制,或者说CMA是处于需要连续内存块的其他内核模块(例如DMA mapping framework)和内存管理模块之间的一个中间层模块。

        CMA同时也用于解决大内存预留带来的内存碎片,同时支持在预留内存空闲时返回系统使用,充分利用内存空间。

2.2 预留内存的声明

        预留内存可以指定常用的属性,常见有:

        (1). reusable:表示当前的内存区域除了被dma使用之外,还可以被内存管理(buddy)子系统reuse。

        (2). no-map:表示是否需要创建页表映射,对于通用的内存,必须要创建映射才可以使用,共享CMA是可以作为通用内存进行分配使用的,因此必须要创建页表映射。

        (3). linux,cma-default:如果要cma区域为共享区域,需要配置上linux,cma-default属性。 指定了 linux,cma-default 属性,内核在分配 cma 内存时会将这片内存当成默认的 cma 分配池使用,执行内存申请时如果没有指定对应的 cma 就使用默认 cma pool。

        (4). alignment:对齐参数,保留内存的起始地址需要向该参数对齐

        (5). alloc-ranges:指定可以用来申请动态保留内存的区间.

        (6). shared-dma-pool(compatible="shared-dma-pool"):

        有的时候设备驱动程序需要采用DMA的方式使用预留的内存,对于这种场景,可以dts中的节点属性设置为shared-dma-pool,从而生成为特定设备驱动程序预留的DMA内存池。这样,设备驱动程序仅需要以常规方式使用DMA API。

2.3 内核配置

        Linux要支持CMA内存,通过dma接口使用CMA内存池内存,需要打开以下配置:

CONFIG_DMA_CMA=y
CONFIG_CMA=y

也可大小相关调试开关

CONFIG_CMA_DEBUG=y
CONFIG_CMA_DEBUGFS=y

3 Linux下使用cma

        本节主要介绍驱动如何使用Linux的cam来预留内存方法,分别有预留内存给专门的设备驱动、通过DMA的API来预留内存、使用CAM内存池预留内存。同时Linux也支持通过启动参数来预留内存。

3.1 预留内存给专门设备驱动

        预留内存给设备驱动,不再将这些内存给系统使用时,需要在设备树申明no-map。如下设备树声明:

reserved-memory {#address-cells = <1>;#size-cells = <1>;ranges;...test_reserver_sh:test_reserver_sh_region@70000000 {compatible = "shared-dma-pool";reg = <0x70000000 0x6000000>;no-map;};
...
};
camsh_lab:camsh_lab {compatible = "test,cam_m_sh";memory-region = <&test_reserver_sh>;status = "okay";};

        在代码中使用:

static struct cma_lab_ampdata cmash_lab_amp = {.name = "lab_of_cma_sh",.type = TEST_CMA_SHARED,
};static const struct of_device_id memory_cam_lab_match[] = {{.compatible = "test,cam_m",.data = &cma_lab_amp,},{.compatible = "test,cam_m_sh",.data = &cmash_lab_amp,},{.compatible = "test,cam_m_pool",.data = &cmash_lab_pool,},{}
};
MODULE_DEVICE_TABLE(of, memory_cam_lab_match);static int cma_lab_probe(struct platform_device *pdev)
{const struct cma_lab_ampdata *cma_match_data = NULL;struct device *dev = &pdev->dev;unsigned int dma_addr = 0;void *addr;struct device_node* dev_node;struct resource res;void* base;int ret = 0;dev_info(dev, "cma data probe hit\n");cma_match_data = of_device_get_match_data(&pdev->dev);if (!cma_match_data) {dev_err(dev, "get driver data fail\n");return -ENODEV;}dev_info(dev, "test cma type %s, name %s\n", cma_match_data->type == TEST_CMA_PRIV?"private":"shared", cma_match_data->name);if(cma_match_data->type == TEST_CMA_PRIV) {...} else if(cma_match_data->type == TEST_CMA_SHARED) {/* Initialize reserved memory resources */ret = of_reserved_mem_device_init(dev);if(ret) {dev_err(dev, "Could not get reserved memory\n");goto out_free_pages;}/* Allocate memory */dma_set_coherent_mask(dev, 0xFFFFFFFF);addr = dma_alloc_coherent(dev, PAGE_SIZE, &dma_addr, GFP_KERNEL);dev_info(dev, "get virtual addr 0x%p\n", addr);dev_info(dev, "get phy addr 0x%x\n", dma_addr);} else if(cma_match_data->type == TEST_CMA_POOL) {...} else {dev_info(dev, "err of type %d\n", cma_match_data->type);return -ENODEV;}return 0;
out_free_pages:if(cma_match_data->type == TEST_CMA_SHARED) {dma_free_coherent(dev, PAGE_SIZE, addr, dma_addr);}return -ENXIO;
}

 运行结果

        内核日志:

        驱动日志:

3.2 通过DMA的API来预留内存

        通过获取设备树的预留内存信息后,使用dma接口初始化内存为预留内存,设备树声明如下:

   reserved-memory {#address-cells = <1>;#size-cells = <1>;ranges;
...test_reserver_priv:test_reserver_priv@77000000 {reg = <0x77000000 0x00700000>;no-map;};
...
};memory_cam_lab:memory_cam_lab {compatible = "test,cam_m";contiguous-area = <&test_reserver_priv>;status = "okay";};

驱动中引用:

static struct cma_lab_ampdata cma_lab_amp = {.name = "lab_of_cma",.type = TEST_CMA_PRIV,
};
static const struct of_device_id memory_cam_lab_match[] = {{.compatible = "test,cam_m",.data = &cma_lab_amp,},...
};
MODULE_DEVICE_TABLE(of, memory_cam_lab_match);static int cma_lab_probe(struct platform_device *pdev)
{const struct cma_lab_ampdata *cma_match_data = NULL;struct device *dev = &pdev->dev;unsigned int dma_addr = 0;void *addr;struct device_node* dev_node;struct resource res;void* base;int ret = 0;dev_info(dev, "cma data probe hit\n");cma_match_data = of_device_get_match_data(&pdev->dev);if (!cma_match_data) {dev_err(dev, "get driver data fail\n");return -ENODEV;}dev_info(dev, "test cma type %s, name %s\n", cma_match_data->type == TEST_CMA_PRIV?"private":"shared", cma_match_data->name);if(cma_match_data->type == TEST_CMA_PRIV) {dev_node = of_parse_phandle(pdev->dev.of_node, "contiguous-area", 0);ret = of_address_to_resource(dev_node, 0, &res);if (ret) {dev_err(dev, "Failed to parse contiguous-area\n");return -EINVAL;}base =memremap(res.start, resource_size(&res), MEMREMAP_WB);dev_info(dev, "paddr:0x%x  vaddr:0x%p\n", (unsigned int)res.start, base);} else if(cma_match_data->type == TEST_CMA_SHARED) {...} else if(cma_match_data->type == TEST_CMA_POOL) {....} else {dev_info(dev, "err of type %d\n", cma_match_data->type);return -ENODEV;}return 0;
out_free_pages:if(cma_match_data->type == TEST_CMA_SHARED) {dma_free_coherent(dev, PAGE_SIZE, addr, dma_addr);}return -ENXIO;
}

        驱动日志:

3.3 使用CMA内存池

        使用CMA内存池,允许系统在内存空闲时回收使用这些内存,驱动可通过cma预留内存接口,获取使用CMA内存池的内存,设备树声明如下:

 reserved-memory {#address-cells = <1>;#size-cells = <1>;ranges;...test_reserver_cam:test_reserver_cam_region@78000000 {compatible = "shared-dma-pool";reg = <0x78000000 0x6000000>;reusable;linux,cma-default;};
};memory_cam_pool:memory_cam_pool {compatible = "test,cam_m_pool";status = "okay";memory-region = <&test_reserver_cam>;};

在设备驱动中使用内存池:

static int cma_lab_probe(struct platform_device *pdev)
{const struct cma_lab_ampdata *cma_match_data = NULL;struct device *dev = &pdev->dev;unsigned int dma_addr = 0;void *addr;struct device_node* dev_node;struct resource res;void* base;int ret = 0;dev_info(dev, "cma data probe hit\n");cma_match_data = of_device_get_match_data(&pdev->dev);if (!cma_match_data) {dev_err(dev, "get driver data fail\n");return -ENODEV;}dev_info(dev, "test cma type %s, name %s\n", cma_match_data->type == TEST_CMA_PRIV?"private":"shared", cma_match_data->name);if(cma_match_data->type == TEST_CMA_PRIV) {...} else if(cma_match_data->type == TEST_CMA_SHARED) {...} else if(cma_match_data->type == TEST_CMA_POOL) {struct page *page;void *virt_addr;phys_addr_t phys_addr;size_t size = 1024 * 1024; // 申请1MB内存 dev->dma_parms = &(struct device_dma_parameters){.max_segment_size = UINT_MAX,};// 2. 设置DMA掩码(确保地址范围合法)dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));// 3. 申请CMA内存 page = dma_alloc_contiguous(dev, size, GFP_KERNEL);if (!page) {dev_err(dev, "Failed to allocate CMA memory\n");return -ENOMEM;}// 4. 获取物理地址和虚拟地址 phys_addr = page_to_phys(page);virt_addr = page_address(page);dev_info(dev, "CMA allocated: phys=0x%llx, virt=%p\n", (u64)phys_addr, virt_addr);} else {dev_info(dev, "err of type %d\n", cma_match_data->type);return -ENODEV;}return 0;
out_free_pages:if(cma_match_data->type == TEST_CMA_SHARED) {dma_free_coherent(dev, PAGE_SIZE, addr, dma_addr);}return -ENXIO;
}static struct cma_lab_ampdata cmash_lab_pool = {.name = "lab_of_cma_pool",.type = TEST_CMA_POOL,
};
static const struct of_device_id memory_cam_lab_match[] = {....{.compatible = "test,cam_m_pool",.data = &cmash_lab_pool,},{}
};
MODULE_DEVICE_TABLE(of, memory_cam_lab_match);

如上使用了cma内存预留接口 dma_alloc_contiguous,也可使用原始dma接口获取cma内存池的内存。最终都调用了cam_alloc接口。

内核日志:

驱动日志:

3.4 通过启动参数预留内存

        通过启动参数也可以为CMA预留内存,该方式预留的内存,将和系统公用,即在预留内存空闲时,将被系统使用,与上一节“使用CMA内存池”效果一样。

        在启动参数声明的cma标签语法如下:

 cma=nn[MG]@[start[MG][-end[MG]]][KNL,CMA]Sets the size of kernel global memory area forcontiguous memory allocations and optionally theplacement constraint by the physical address range ofmemory allocations. A value of 0 disables CMAaltogether. For more information, seekernel/dma/contiguous.c

        以下是笔者的实际例子:

setenv bootargs "init=/linuxrc root=/dev/mmcblk0p2 rw rootwait earlyprintk console=ttyAMA0 cma=96M@0x78000000"

        即在0x78000000开始处,预留96M(0x6000000)的内存。加载后得到日志如下:

驱动仍然使用3.3节的代码,从内存池里取内存使用,实际分配的地址为0x78100000不是0x78000000,前面1M用于CMA数据管理。

4 关于内存大小声明

        CMA内存声明预留内存大小和基地址,都要进行页内存对齐,否则将预留失败,一般页大小为4K,也有4M的页大小,根据具体平台而定,VP平台是4M空间,所以如果配置的内存没有4M对齐会失败。

        如下是一个大小(0x600000)没有对齐的结果:可看到第三个预留内存打印incorrect alignment of CMA region,预留内存对齐不合法失败。

正常预留日志:

5 完整测试代码

        设备树:

   reserved-memory {#address-cells = <1>;#size-cells = <1>;ranges;/* Chipselect 3 is physically at 0x4c000000 */vram: vram@4c000000 {/* 8 MB of designated video RAM */compatible = "shared-dma-pool";reg = <0x4c000000 0x00800000>;no-map;};test_reserver_sh:test_reserver_sh_region@70000000 {compatible = "shared-dma-pool";reg = <0x70000000 0x6000000>;no-map;};test_reserver_priv:test_reserver_priv@77000000 {reg = <0x77000000 0x00700000>;no-map;};test_reserver_cam:test_reserver_cam_region@78000000 {compatible = "shared-dma-pool";reg = <0x78000000 0x6000000>;reusable;linux,cma-default;};};camsh_lab:camsh_lab {compatible = "test,cam_m_sh";memory-region = <&test_reserver_sh>;status = "okay";};memory_cam_lab:memory_cam_lab {compatible = "test,cam_m";contiguous-area = <&test_reserver_priv>;status = "okay";};memory_cam_pool:memory_cam_pool {compatible = "test,cam_m_pool";status = "okay";memory-region = <&test_reserver_cam>;};

        驱动代码:

#include <linux/device.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/dma-map-ops.h>#define TEST_CMA_PRIV 2
#define TEST_CMA_SHARED 1
#define TEST_CMA_POOL 3
typedef struct cma_lab_ampdata {const char *name;unsigned int type;
}cma_lab_ampdata_t;
static int cma_lab_probe(struct platform_device *pdev)
{const struct cma_lab_ampdata *cma_match_data = NULL;struct device *dev = &pdev->dev;unsigned int dma_addr = 0;void *addr;struct device_node* dev_node;struct resource res;void* base;int ret = 0;dev_info(dev, "cma data probe hit\n");cma_match_data = of_device_get_match_data(&pdev->dev);if (!cma_match_data) {dev_err(dev, "get driver data fail\n");return -ENODEV;}dev_info(dev, "test cma type %s, name %s\n", cma_match_data->type == TEST_CMA_PRIV?"private":"shared", cma_match_data->name);if(cma_match_data->type == TEST_CMA_PRIV) {dev_node = of_parse_phandle(pdev->dev.of_node, "contiguous-area", 0);ret = of_address_to_resource(dev_node, 0, &res);if (ret) {dev_err(dev, "Failed to parse contiguous-area\n");return -EINVAL;}base =memremap(res.start, resource_size(&res), MEMREMAP_WB);dev_info(dev, "paddr:0x%x  vaddr:0x%p\n", (unsigned int)res.start, base);} else if(cma_match_data->type == TEST_CMA_SHARED) {/* Initialize reserved memory resources */ret = of_reserved_mem_device_init(dev);if(ret) {dev_err(dev, "Could not get reserved memory\n");goto out_free_pages;}/* Allocate memory */dma_set_coherent_mask(dev, 0xFFFFFFFF);addr = dma_alloc_coherent(dev, PAGE_SIZE, &dma_addr, GFP_KERNEL);dev_info(dev, "get virtual addr 0x%p\n", addr);dev_info(dev, "get phy addr 0x%x\n", dma_addr);} else if(cma_match_data->type == TEST_CMA_POOL) {struct page *page;void *virt_addr;phys_addr_t phys_addr;size_t size = 3 * 1024 * 1024; // 申请1MB内存 // dev->dma_parms = &(struct device_dma_parameters){//  .max_segment_size = UINT_MAX,// };// 2. 设置DMA掩码(确保地址范围合法)// dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));// 3. 申请CMA内存 page = dma_alloc_contiguous(dev, size, GFP_KERNEL);if (!page) {dev_err(dev, "Failed to allocate CMA memory\n");return -ENOMEM;}// 4. 获取物理地址和虚拟地址 phys_addr = page_to_phys(page);virt_addr = page_address(page);dev_info(dev, "CMA allocated: phys=0x%llx, virt=%p\n", (u64)phys_addr, virt_addr);} else {dev_info(dev, "err of type %d\n", cma_match_data->type);return -ENODEV;}return 0;
out_free_pages:if(cma_match_data->type == TEST_CMA_SHARED) {dma_free_coherent(dev, PAGE_SIZE, addr, dma_addr);}return -ENXIO;
}
static struct cma_lab_ampdata cma_lab_amp = {.name = "lab_of_cma",.type = TEST_CMA_PRIV,
};
static struct cma_lab_ampdata cmash_lab_amp = {.name = "lab_of_cma_sh",.type = TEST_CMA_SHARED,
};
static struct cma_lab_ampdata cmash_lab_pool = {.name = "lab_of_cma_pool",.type = TEST_CMA_POOL,
};
static const struct of_device_id memory_cam_lab_match[] = {{.compatible = "test,cam_m",.data = &cma_lab_amp,},{.compatible = "test,cam_m_sh",.data = &cmash_lab_amp,},{.compatible = "test,cam_m_pool",.data = &cmash_lab_pool,},{}
};
MODULE_DEVICE_TABLE(of, memory_cam_lab_match);
static struct platform_driver cma_lab_driver = {.probe = cma_lab_probe,.driver = {.name = "cma_test",.of_match_table = of_match_ptr(memory_cam_lab_match),},
};
static int __init cmatest_init(void)
{int ret = 0;ret = platform_driver_register(&cma_lab_driver);if (ret)printk(KERN_ERR "platform_driver_register fail %d", ret);printk(KERN_INFO "%s:%d exit\n", __func__, __LINE__);return 0;
}
module_init(cmatest_init);
static void __exit cmatest_exit(void)
{printk(KERN_INFO "%s:%d exit\n", __func__, __LINE__);
}
module_exit(cmatest_exit);
// module_platform_driver(cma_lab_driver);
MODULE_AUTHOR("vincent.donnal@bb.com");
MODULE_DESCRIPTION("a verifying using of cma driver");
MODULE_LICENSE("GPL v2");

        内核和驱动打印日志:

6 查看内存分配情况

6.1 查看cma分配

        通过/proc/meminfo查看cma分配内存大小和使用大小

一共分配了96M,使用了3M空间。

6.2 查看系统能使用的内存大小

        通过/proc/iomen查看sysram大小

        其中0x70000000 - 0x76000000和0x77000000 - 0x77700000预留专门设备驱动,不计入系统内存。

7 附录

http://www.dtcms.com/wzjs/804736.html

相关文章:

  • WordPress 百度 不收入太原seo排名
  • jsp商务网站建设手机显示的网站该怎样设计
  • 一个学校怎么制作网站商务网站建设与维护 课件
  • 网站加速器下载公司注册地址规定
  • 国外创意网站设计欣赏智慧门店管理服务平台
  • 网站开发运营维护方案建议sem网络营销
  • 凡科注册的网站怎么被百度收录南京建设网页培训班
  • 在线制作简历网站河南seo公司
  • 昆明网站快速优化排名学做网站多长时间
  • 沧州最火网站女生学市场营销好吗
  • 建设企业网站的目的c#网站开发技术
  • 徐州网站制作如何定位网站做游客留言做
  • 东莞网站建设 环保设备一个专门做预告片的网站
  • 有没有教做网站实例视频西安旅游攻略必去景点推荐
  • 58网站怎么做浏览度才高网站开发公司名称
  • 七牛云如何做网站缓存织梦怎么做网站地图
  • 一个网站备案多个域名吗学生网站建设的心得
  • 商务网站开发的的基本流程宝安网站设计项目
  • 苏州网站建设店铺装修免费手机网站自助建站
  • 免费大数据网站古风网站怎么做
  • 游戏网站推广衡水建设网站
  • 南京网站开发选南京乐识好淘宝网网页版首页登录入口
  • 天津开发区建网站公司网站推广 html关键词代码解说
  • 长春网站建设seo攸县网页设计
  • 南阳网站关键词查收录
  • 网站备案 加急做视频网站需要什么空间
  • 网站设计开发工程师网站建设需要什么材料
  • 网站维护推广的方案个人简历模板下载免费
  • 广安建设局网站长沙网络营销公司有哪些
  • 萝卜建站wordpress验证码代码