arm-linux内存管理学习笔记(3)-页表前戏

深入Linux内核(内存篇)—页表映射分页 深入Linux内核(内存篇)—页表映射一、分页二、X86中的分页三、ARM中的分页四、Kernel中的分页 操作系统的核心任务是对系统资源的管理,而重中之重的是对CPU和内存的管理。为了使进程摆脱系统内存的制约,用户进程运行在虚拟内存之上,每个用户进程都拥有完整的虚拟地址空间,互不干涉。 而实现虚拟内存的关键就在于建立虚拟地址(Virtual Address,VA)与物理地址(Physical Address,PA)之间的关系,因为无论如何数据终究要存储到物理内存中才能被记录下来。 如下图所示,进程1和进程 阅读详情

start_kernel之前的汇编代码建立了内核临时页表,完成了内核区域的静态线性映射,保证内核可以在舒适的虚拟地址空间(运行地址和链接地址一致)运行。进入start_kernel之后就要准备建立完整的页表映射,这部分工作是在paging_init中完成。
不过在建立完整页表映射之前还需要进行一些准备工作,本文来分析下。
为了简化整个代码流程,便于分析,我的设备内核配置为不使用高端内存,不配置CONFIG_HIGHMEM。bootargs中传给内核的mem=256.
内核版本号:3.4.55
paging_init是在start_kernel的setup_arch中调用,这里按照先后顺序对setup_arch跟页表相关的各个函数功能做个介绍,重点函数paging_init进行详细分析。
setup_processor:调用lookup_processor_type,跟head.S中__lookup_processor_type一样,获取存储在.proc.info.init段中与cpu id一致的proc_info_list结构体,该结构体中存储着处理器的一些特性。打印出cpu的一些相关信息(如版本号 cache属性等)。

setup_machine_tags:对uboot传递来的tags进行解析,获取mem cmdline等信息,具体过程可以参考我分析kernel传参的博文,链接:http://blog.youkuaiyun.com/skyflying2012/article/details/35787971

parse_early_param:对boot_command_line进行早期的解析,具体解析原理可以参考我分析kernel参数解析的博文,链接:http://blog.youkuaiyun.com/skyflying2012/article/details/41142801
与页表相关的是对mem的解析,相应的解析函数如下。

{
    static int usermem __initdata = 0;
    unsigned long size;
    phys_addr_t start;
    char *endp;

    /*
     * If the user specifies memory size, we
     * blow away any automatically generated
     * size.
     */
    if (usermem == 0) {
        usermem = 1;
        meminfo.nr_banks = 0;
    }

    start = PHYS_OFFSET;
    size  = memparse(p, &endp);
    if (*endp == '@')
        start = memparse(endp + 1, NULL);

    arm_add_memory(start, size);

    return 0;
}
early_param("mem", early_mem);

我的设备内存起始物理地址是0x80000000,即PHYS_OFFSET = 0x80000000,cmdline中mem=256m,
early_mem最终调用arm_add_memory将0x80000000起始的256MB内存添加到meminfo的membank数组中。meminfo中记录着系统有多少块连续内存,用membank数组记录,这里我们仅使用1个membank表示0x80000000起始的256MB内存空间。

sanity_check_meminfo:对meminfo中所有的membank进行范围检查,不能覆盖最小的vmalloc区域,将lowmem_limit设置为最高membank的顶端,我的设备只有一个membank,因此lowmem_limit为0x90000000,这是内存物理地址。最后将high_memory设置为lowmem_limit的虚拟地址,lowmem是线性映射到0xc0000000,因此high_memory=0xd0000000。
static void * __initdata vmalloc_min = (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
我的设备VMALLOC_END=0xfc000000,这是vmalloc区域的上限,VMALLOC_OFFSET=0x800000,是vmalloc区域与lowmem之间8MB的隔离带。这样计算vmalloc_min是0xec800000,这是一个最小(240MB)的vmalloc区域.

arm_memblock_init:全局结构体memblock用来记录内存中可用和保留的区域,memblock.memory代表可用区域,memblock.reserved代表保留区域。arm_memblock_init中首先将meminfo中记录的membank添加到可用区域中。将kernel的代码段 数据段以及ramdisk区域都添加到保留区域,再将一级页目录的16KB区域添加到保留区域。
最后如果在板级结构体machine_desc定义了reserve函数,则会调用该函数完成板级相关的一些内存区域的保留。
为了方便调试,可以在cmdline中加入memblock=debug,会将memblock中可用和保留的区域全部打印出来。
我的设备是将0x80000000起始的256MB区域添加到可用区域memblock.memory中。
以上完成了对meminfo memblock的初始化,需要注意,其中存储的都是物理地址。

接下来调用paging_init,其中与页表建立相关的函数如下。在arch/arm/mm/mmu.c中

 build_mem_type_table();
    prepare_page_table();
    map_lowmem();
    devicemaps_init(mdesc);
    kmap_init();

    top_pmd = pmd_off_k(0xffff0000);

其中map_lowmem devicemaps_init kmap_init完成了完整页表的建立,下篇文章再详细分析,这里先不说了。
build_mem_type_table:完成对kernel中mem_types数组的修复和补充。mem_types数组是kernel记录当前系统映射不同地址空间类型(普通内存 设备内存 IO空间等)的页表属性,其中页表属性还包括section-mapping的属性prot_sect,以及page-mapping的一级页目录属性prot_l1,二级页表属性prot_pte.
不过要注意的是,mem_types中prot_sect prot_l1都与硬件属性一一对应。但二级页表属性值prot_pte是linux定义的软件页表属性,而不是硬件页表属性,本文最后说明linux与arm适配问题会再详说。
在kernel下页表建立函数create_mapping中会根据选定的mem_types成员来设置当前映射所需的二级软件页表属性,最后会调用处理器相关的set_pte_ext,首先设置软件页表项,然后在根据软件页表项值配置硬件页表项。(linux在建立完整第二级页表时使2个硬件页表相连,并且在其后添加2个软件页表,保证这一页空间被充分利用,文末再细说)
build_mem_type_table中跟处理器特性对mem_types数组成员(各个类型的地址空间)的各个页表属性进行修改补充。软件开发人员一般不需要修改,除非处理器核做过修改。
接下来我们来分析下本文的关键函数prepare_page_table。在arch/arm/mm/mmu.c中

static inline void prepare_page_table(void)
{
    unsigned long addr;
    phys_addr_t end;

    /*
     * Clear out all the mappings below the kernel image.
     */
    for (addr = 0; addr < MODULES_VADDR; addr += PMD_SIZE)
        pmd_clear(pmd_off_k(addr));

#ifdef CONFIG_XIP_KERNEL
    /* The XIP kernel is mapped in the module area -- skip over it */
    addr = ((unsigned long)_etext + PMD_SIZE - 1) & PMD_MASK;
#endif
    for ( ; addr < PAGE_OFFSET; addr += PMD_SIZE)
        pmd_clear(pmd_off_k(addr));

    /*
     * Find the end of the first block of lowmem.
     */
    end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
    if (end >= lowmem_limit)
        end = lowmem_limit;

    /*
     * Clear out all the kernel space mappings, except for the first
     * memory bank, up to the vmalloc region.
     */
    for (addr = __phys_to_virt(end);
         addr < VMALLOC_START; addr += PMD_SIZE)
        pmd_clear(pmd_off_k(addr));
}

该函数是在建立完整页表前对一级页目录(swapper_pg_dir)进行清空,便于建立页表时对空页目录项进行判断然后分配。不过并不是所有页目录项都清空,我们知道虚拟地址的高12bit是16K一级页目录的索引ndex,prepare_page_table中对于第一块membank(lowmem部分)虚拟地址空间映射的页目录项跳过,不进行清空操作。
以我的设备为例,第一块也是唯一一块membank是0x80000000起始的256MB。lowmem_limit也是0x90000000。这块空间是线性映射,由0x80000000映射到0xc0000000。因此在4KB个页目录项中,第0xc00到第0xd00这256个页目录项,prepare_page_table不进行清空。
根据上一篇内核临时页表建立的分析,head.S中建立的临时页表,主要完成了3个地址空间的映射。
(1)turn_mmu_on所在1M空间的平映射
(2)kernel image的线性映射
(3)atags所在1M空间的线性映射
我计算过我的设备中,临时页表中kernel image线性映射了大约12MB空间,也就是第0xc00之后的12个页目录项。prepare_page_table中跳过0xc00开始的256个,临时页表建立的kernel image线性映射没有破坏,kernel的运行环境得到了保证。
不过为了保证mmu使能后的平滑跳转而建立的1MB平映射(vaddr从0x80000000到0x8100000),在prepare_page_table中就被清空了。
prepare_page_table整个流程如下。
1 对虚拟地址0到MODULES_VADDR(0xc0000000以下8MB或16MB的地址)的一级页目录项进行清空
2 对MODULES_VADDR到PAGE_OFFSET(0xc0000000)的一级页目录项进行清空
3 对lowmem顶端到VMALLOC_START的一级页目录项进行清空
我们来分析下具体的清空过程,以流程1为例。
从0到MODULES_VADDR,对每2MB空间,调用pmd_clear(pmd_off_k(addr))。
pmd_off_k定义如下。在arch/arm/mm/mm.h中

static inline pmd_t *pmd_off_k(unsigned long virt)
{
    return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt);
}

arm-linux仅使用2级页表,pud_offset
pmd_offset不做任何操作,直接返回参数,直接来看pgd_offset_k,如下。

extern pgd_t swapper_pg_dir[PTRS_PER_PGD];

/* to find an entry in a page-table-directory */
#define pgd_index(addr)     ((addr) >> PGDIR_SHIFT)

#define pgd_offset(mm, addr)    ((mm)->pgd + pgd_index(addr))

/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(addr)  pgd_offset(&init_mm, addr)

PGDIR_SHIFT定义为21,pgd_offset_k获取到了一级页目录项的虚拟地址,但是需要注意的是,该地址是8字节对齐。再来看pmd_clear,如下。在./arch/arm/include/asm/pgtable-2level.h

#define pmd_clear(pmdp)         \
    do {                \
        pmdp[0] = __pmd(0); \
        pmdp[1] = __pmd(0); \
        clean_pmd_entry(pmdp);  \
    } while (0)

将连续的2个页目录项清空,并且清空相应的TLB缓存。
综上,prepare_page_table清空具体流程是,对指定地址空间以2MB为一次操作单元,每次操作连续清空对应的2个一级页目录。
这就奇怪了,按照之前我们介绍的arm硬件页表机制,一级页目录共4096个,每个映射1MB空间,不应该一次操作1MB吗,为啥要以2MB为单位?

理解内核的这种做法,文章最后,就要来说明下linux页表机制与arm页表机制的适配问题了,主要有2点。
1 页表深度的适配
2 软件页表和硬件页表配合

1 页表深度的适配
arm硬件页表机制之前详细分析过,这里不再细说了,可以看我这系列的第一篇文章。
linux内核为了适配各种各样的处理器MMU,特别是64位处理器。2.6.11之前使用三级页表,之后开始使用四级页表。
linux内核定义的标准是这样,最高级pgd为页目录表,它找到每个进程mm_struct结构的pgd成员,用它定位到下一级pud,第二级pud定位到下一级pud,第三级pud定位到pte,pte是页表,它就能定位到哪个页了。最后虚拟地址的最后12位定位的是该页的偏移量。大体流程如下:

virt addr —> pgd —> pud —> pmd —> pte —> phy addr

首先需要理解,内存多级页表,是给mmu来解析的,因此针对不同的处理器mmu页表机制,linux需要在配置多级页表时进行调整。
为了能够符合arm mmu的页表解析机制(2级页表),arm-linux实现时砍掉了中间的pud pmd。如上面分析pmd_off_k时pud_offset pmd_offset中不做任何操作,直接返回参数。大体流程如下。

virt addr —> pgd —> pte —> phy addr

这样就保证了linux配置页表时虽然表面上看是4级页表,但是内存中建立却是一个2级页表。arm-mmu可以正确的解析页表,进行地址翻译。

2 软件页表和硬件页表配合
arm硬件页表机制中,每个一级页目录项对应的二级页表空间都是独立分配的,虽然连续2个一级页目录项所映射2MB地址空间是连续的虚拟地址空间,但是用来存储二级页表的空间之间是没有什么关系的。
不过arm-linux内核为了实现高效的内存管理,做了一个很巧妙的安排。
我们知道1个一级页目录项对应的二级页表是256x4 = 1024字节。arm-linux将2个连续的一级页目录项对应的2个二级页表分配在一起。而且还在这2个二级硬件页表之下在建立2个对应的二级软件页表,一共是4KB,正好占用1页空间。如下。

*    pgd             pte
 * |        |
 * +--------+
 * |        |       +------------+ +0
 * +- - - - +       | Linux pt 0 |
 * |        |       +------------+ +1024
 * +--------+ +0    | Linux pt 1 |
 * |        |-----> +------------+ +2048
 * +- - - - + +4    |  h/w pt 0  |
 * |        |-----> +------------+ +3072
 * +--------+ +8    |  h/w pt 1  |
 * |        |       +------------+ +4096

对于这样的安排在./arch/arm/include/asm/pgtable-2level.h有详细的英文解释。
我们告诉linux内核arm一级页目录项是8 bytes,一共是2048个。配置页目录项时,一次分配4KB空间,高2KB空间每1KB的物理基地址依次写入8 bytes一级页目录项的2个word中。
我的理解,arm-linux如此安排的原因有二。
(1)减少空间浪费,一个页目录项仅对应1024字节的页表,这样页表初始化时,按页分配的空间仅能使用1KB,其余3KB空间浪费,如上安排,可以完全利用这4KB页。
(2)linux软件二级页表属性位定义与arm硬件二级页表不一致(软件二级页表位定义在arch/arm/include/asm/pgtable-2level.h,硬件二级页表位定义在arch/arm/include/asm/pgtable-2level-hwdef.h,其中有详细说明),有些属性arm硬件页表没有,如dirty,accessed,young等,因此使用软件页表进行模拟兼容。arm-mmu读取硬件2级页表进行地址翻译,而第二级的软件页表仅仅留给linux来配置和读取。最终配置二级页表的set_pte_ext也会设置完软件页表后,在根据软件页表属性值来配置硬件页表。

所以我们在arm-linux内核中看到各种相关宏定义都表示,linux看到的arm一级页目录项有2048个,每个页目录项8
bytes,二级页表项是512个。不过arm-mmu的硬件机制还是4096个一级页目录项,每个页表有256个页表项。
两种机制是靠2个相邻页目录项的页表存储空间连续来平滑过渡的。

到这里,完整页表建立的准备工作做完了,主要是建立meminfo
memblock,并清空页目录项,但是保留了lowmem所在的线性映射页目录项,保障kernel正常运行。下篇文章就来分析下具体页表建立的过程!

Exynos4412 内核移植(六)—— 设备树解析 一、描述         ARM Device Tree起源于OpenFirmware (OF),在过去的Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及 阅读详情

相关推荐

arm-linux内存管理学习笔记(1)-内存页表的硬件原理

学习内核的内存管理如果脱离了MMU的硬件原理,只去学习其软件逻辑,真的很难懂。说到底,软件代码的逻辑是为硬件服务,只是为了充分发挥硬件的各项功能,因此学习linux的内存管理机制,首先要学习下该处理器架构下MMU的工作原理,这样对我们理解页表机制的逻辑很有帮助

做一个有技术追求的人 8631

Linux启动过程分析(十一)-----customize_machine(注册开发板相关硬件信息)

初始化过程进行到下面这一步: c0599c48 t __initcall_customize_machine3 调用的函数及其位置如下: Setup.c (arch\arm\kernel):arch_initcall(customize_machine) static int __init customize_machine(void) { /* customizes platform dev...

qq_40788950的博客 1186

arm-linux内存管理学习笔记(2)-内核临时页表的建立

需要搞明白的是,linux系统上执行./a.out运行,其实并不是运行的a.out这个elf文件。内核对于要运行的elf文件会调用load_elf_binary进行解析,首先是根据elf文件的header信息获取它需要的解释器,然后加载需要运行的各个段到内存中,把控制权交给解释器,解释器会加载该程序需要动态链接库(静态链接就不运行解释器),最后解释器将控制权交给内存中的程序入口,程序运行。

做一个有技术追求的人 6910

Linux内存管理(四):paging_init分析

上文介绍了启动页表的创建,通过fix map建立DTB物理地址的映射,以及memblock管理物理内存。现在我们能够通过memblock进行物理内存的分配,但分配的内存还不能够进行访问,我们需要对memblock管理的内存进行映射,这就是paging_init的一部分工作 paging_init void __init paging_init(void) { pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir)); -------- (1

Hober 6176

linux内存管理之页表

什么是页表页表就是用于将虚拟地址转换为物理地址的转换关系表。访问虚拟地址时,计算机通过页表找到对应的实际物理地址访问。为何需要多级页表目前在linux中采用4级页表,ARM32采用2级页表,ARM64采用4级页表。但linux是一个通用性的系统,当ARM32时2级页表也是使用linux的4级页表机制,只是将其它两级页表转换不做任何处理。 那么为什么需要多级页表呢?节省内存空间。二级页表可以在需要的

小二的博客 2931

Linux内存管理(13):paging_init 详解

从memblock初始化一文中得知在调用之前,存放 Kernel Image 和DTB 两端物理内存区域可以访问 (相应的页表已经建立好)。在 memblock 初始化之后,物理内存已经添加到系统,但是这部分的物理内存到虚拟内存的映射还没有建立,可以通过 memblock_alloc() 分配一段物理内存,但是无法访问,一切还需要等待之后,建立最终的页表,从而实现物理内存到虚拟内存的映射。VA_BITS=39, PAGE_SHIFT=12(每页4K)本文重点剖析了。

私房菜 1499

内存映射过程之paging_init

内存映射过程之paging_init 导读 之前已经逐步整理完成了idmap、fixup、memblock等内容,在此阶段已经可以: 访问kernel image的地址空间; 访问FDT地址空间,即已经获取device tree相关数据; 可以通过memblock提供的接口申请内存; 则接下来需要做的处理,是要把从fdt中获取的mem layout关系建立实际的映射; 所谓建立映射,实质很简单,即根据页表大小和地址空间大小,填充PUD PMD PTE等数据; 1. 页表转换关系 这部分之前已经整理过了,

And乔的博客 1778

从FrSky到TBS:深度解析航模2.4G遥控协议江湖史(附ELRS高频头改装指南)

本文深度解析了航模2.4G遥控协议的技术演进史,从FrSky ACCST的兴衰到TBS Crossfire的崛起,再到开源协议ExpressLRS的革命性突破。文章不仅对比了各协议在延迟、距离与抗干扰能力上的技术内核,还提供了为多协议遥控器加装TBS Crossfire高频头的实战改装指南,帮助玩家打通协议壁垒,提升飞行体验。

weixin_29193259的博客 737

内存管理——页表

Linux内核页表管理-那些鲜为人知的秘密 1.开场白 环境: 处理器架构:arm64 内核源码:linux-5.11 ubuntu版本:20.04.1 代码阅读工具:vim+ctags+cscope 通用操作系统,通常都会开启mmu来支持虚拟内存管理,而页表管理是在虚拟内存管理中尤为重要,本文主要以回答几个页表管理中关键性问题来解析Linux内核页表管理,看一看页表管理中那些鲜为人知的秘密。 2.页表的作用是什么? 1)地址转换 将虚拟地址转换..

u014426028的博客 1万+

OpenClaw 完整部署教程

版本:OpenClaw 2026.2.13更新日期:2026-02-26适用系统:Linux (Ubuntu/Debian/CentOS)

qq_39436086的博客 2318

转子动力学 | 临界速度与稳定性分析

本文深入探讨了转子动力学中的核心问题——临界速度与稳定性分析。临界速度是旋转机械发生共振的危险转速,通过模态分析和坎贝尔图可进行预测。文章还剖析了油膜涡动等稳定性问题,并结合ANSYS仿真案例,详细阐述了从建模、分析到设计优化的完整工程实践流程,为旋转机械的可靠设计与安全运行提供关键指导。

weixin_29313239的博客 518

ARM64 MMU和系统上电时Linux页表映射过程

1、MMU

进步源于记录,优秀来自分享 2966

最新小旋风蜘蛛池X6.21解密版+绕过授权带教程

介绍: 1.站群管理:用你的域名在这里添加网站 2.站点优化:站点互链,内容优化 2.系统设置:开启蜘蛛池 3.采集管理(可开启自动采集) 4.缓存设置:推荐开启tkd缓存 其他的用户根据自己的实际情况后台进行配置,通常以下: 1.后台首页(这里显示系统的大致概况) 2.系统设置:蜘蛛池的基本设置(访问开关、跳转、统计等等) 3.站群管理: 1.网站管理(用你的域名在这里添加网站) 2.模型管理(可构建不同类型站点:电影、文章、论坛等等) 3.TKDB调用模板(即:title、keywords、descri

百度SEO程序下载 2937

arm-linux 内存管理之一级页表及二级页表

arm32 一个 vma 中 有 两个 index // armv6 RM ref P730 L1(一级页表,即页目录表)index 为 12位,所以一级页表的大小为 2^12*4B=16KB L2(二级页表,页表)index为8位,所以二级页表的大小为2^8*4B=1KB // 所以一套(一级和二级)页表的"最大"大小为 // 16KB + 16KB/4B * 1KB = 4MB + 16KB // 一级页表大小 + 所有的 二级页表大小 arm32 硬件上 有 TTBR0 TTBR1

u011011827的博客 3718

昇腾AI处理器Ascend C编程:从C/C++基础到高性能算子开发实战

异构计算是提升AI算力效率的核心技术,通过在CPU之外引入专用处理器(如GPU、NPU)协同工作,实现大规模并行计算。其原理在于将计算密集型任务卸载到专用硬件,利用其高并行架构加速处理。技术价值在于突破传统CPU的算力瓶颈,为深度学习训练与推理提供强大动力,广泛应用于模型部署、科学计算和高性能计算场景。本文聚焦昇腾AI处理器的原生编程语言Ascend C,它基于C/C++标准扩展,通过显式内存管理和任务并行模型,充分发挥达芬奇架构中Cube与Vector单元的性能。针对CANN算子开发,文章详解了从环境搭建

weixin_34411563的博客 368

Open3D 三维重建-Delaunay Triangulation (德劳内三角剖分)

德劳内三角剖分(Delaunay Triangulation)是一种用于从一组点生成三角形网格的算法。它的特点是使得生成的三角形尽量接近等边三角形,即最大化最小角度,避免生成细长的三角形。

纵马踏花向自由 2502

内存管理源码分析-内核页表的创建以及索引方式(基于ARM64以及4级页表)

简介 页表的主要作用是完成虚拟地址到物理地址的转换,更详细的介绍可以参考这个优秀的博客,很好地介绍了页表的理论。Linux如何实现这个页表理论呢?以及如何进行寻址呢?本文将会结合代码,从代码出发,基于ARM64的架构,分析Linux从源码上如何实现页表理论。 从一个页的地址说起 对于ARM64的架构,一个虚拟地址的大小是64bit。但是实际上并不是全部64bit都是用来寻址的,其中一部分bit会基...

Hubery的存储点滴 1938

镜头调焦的 调整的是焦距还是像距?

在镜头 “调焦”(即日常拍照时的)中,调整的核心是,而非焦距。

AIoT深度探索者 | 嵌入式系统架构师 深耕物联网(IoT)与人工智能(AI)融合技术,聚焦​​边缘计算、图像开发、低功耗通信协议​​,致力于智能硬件,关注我获取最新技术文章信息与海量资源~ 1352

#Liunx内存管理# 内核空间的页表存放在什么地方?

内核页表的存放位置取决于处理器架构:ARM32:一级页表固定,二级页表动态分配。x86/ARM64:全部页表动态分配,物理地址由伙伴系统管理。共同原则:页表始终位于内核管理的物理内存中,用户进程无法直接访问或修改。

sinat_37817094的博客 1585

模型训练篇 | 手把手教你使用ResNet训练自己数据集和推理,ResNet50通用物体分类识别,含完整代码和数据集,全网最详细教程

手把手教你使用ResNet训练自己数据集和推理,ResNet50通用物体分类识别,含完整代码和数据集,全网最详细教程。本篇文章将带你学习 ResNet50 模型构建、ResNet50训练自己数据集、数据集处理、推理和验证、模型剪枝与模型改进等。 本篇教程适配各种分类识别任务,可以说是一个通用的教程,只需修改自己的数据集即可完成自己领域的任务和系统实现。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 734

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

arm linux 进程页表,linux内存管理(五)arm页表

最近比较忙,好多天没更新了,后面可能还需要20多篇文章才能把整个内存管理讲透。前面讲述了一个通用的页表机制,以及简单介绍了TLB。今天会介绍arm的页表机制,这里特指32位arm。目前内核提供了一个选项CONFIG_PGTABLE_LEVELS来配置页表的级数。32位的嵌入式系统通常采用2级页表,因为2级页表就足够映射所有内存了。我们以头文件为线索,探寻arm的页表机制。在arm平台下的pgtab...

weixin_35316606的博客 758

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

#Linux内存管理# 在ARM32系统中,页表是如何映射的?在ARM64系统中,页表又是如何映射的?

特性 ARM32 ARM64映射层级 2层(PGD→PTE),支持段映射 4层(PGD→PUD→PMD→PTE),支持动态合并层级页表存储 PGD固定地址,PTE动态分配 全部页表动态分配地址空间 32位虚拟地址(4GB) 48/52位虚拟地址(256TB/4PB)大页支持 1MB段或64KB页 2MB/1GB大页内核映射优化 低端内存线性映射(896MB) 线性映射区覆盖全部物理内存寄存器机制 单TTBR寄存器(内核与用户共用) 双TTBR寄存器(TTBR0用户/TTBR1内核)

sinat_37817094的博客 1613

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【内存管理】页表映射

Linux内核中封装了很多宏来处理页表。

嵌入式与Linux那些事的博客 1562

ARM Linux 页表

2M连续的虚拟地址,如果页框是4K,那么索引就有512个,因为逢4K进1,所以这512个索引也是连续的(0,1,..., 511)!在(1)中,分配页表大小,PTE_HWTABLE_OFF和PTE_HWTABLE_SIZE都是512*sizeof(pte_t),即一共是4K(1024*sizeof(pte_t))一个页表。页框分配后写入页表时,即set_pte_ext,会写入到相对于pte首地址偏移512*sizeof(pte_t)的地址,因为前512*sizeof(pte_t)是给软件用的。

c18976636326的博客 557

内核深入学习3——分析ARM32和ARM64体系架构下的Linux内存区域示意图与页表的建立流程

这篇文章主要记录了是经典的ARM32和ARM64架构下Linux内核的内存布局和页表建立的流程

charlie114514191的博客 1863

Linux内存管理 (2)页表的映射过程

https://www.cnblogs.com/arnoldlu/p/8087022.html 专题:Linux内存管理专题 关键词:swapper_pd_dir、ARM PGD/PTE、Linux PGD/PTE、pgd_offset_k。 Linux下的页表映射分为两种,一是Linux自身的页表映射,另一种是ARM32 MMU硬件的映射。 1. ARM32页表映射 由于ARM32和Linux内...

hbcbgcx的博客 1116
上一篇: Cortex-A8处理器memcpy的优化方案
下一篇: 新的开始,全力以赴!
skyflying2012
博客等级 码龄15年 1911粉丝 128原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值