在这里记录自己的嵌入式学习方向和成果,只做大方向的规划,目前学习规划如下:
√ linux基础学习
√ arm裸机开发(使用正点原子IMX6ULL的板子)
√ linux的系统移植
√ Linux核心驱动开发
√ qt
√ linuxc应用编程
【doing】linux内核源码分析(主要通过以下两本书并结合linux源码进行学习):
- linux内核设计与实现(在看)
- 深入理解linux内核
分析前先看下面这个函数:
1 | .macro get_phy, reg, symbol |
adrp \reg, \symbol
计算symbol相较于pc寄存器的页基地址,可以看成:
1 | reg = (symbol & ~(0xFFF)) - (pc & ~(0xFFF)) + (pc & ~(0xFFF)) |
再通过add \reg, \reg, #:lo12:\symbol将symbol的低12位与reg相加存放回reg中
这么使用是为了解除直接使用ldr reg,=symbol
的限制
首先从内核的入口_start进行分析:
1 | /* Variable registers: x21~x28 */ |
mov dtb_paddr, x0
将设备树的物理地址从x0中取出(由uboot放入x0中)放入dtb_paddr中,由dtb_paddr .req x21
可知dtb_paddr 是寄存器x21的别名,同理,x1-x3中的值会被放入x23-x24中。get_phy stack_top, .boot_cpu_stack_top
将CPU得栈顶地址保存在X25中mov x0, dtb_paddr
将设备树的物理地址放入x0寄存器我们进入init_mmu_early中查看:
1 | init_mmu_early: |
首先获得了early_page_array的物理地址,通过源码可知,early_page_array是预留出来的一片24*4096的地址空间:
1 | .early_page_array: |
再通过 bl set_free_page
将这个地址存入全局变量__init_page_array
中:
1 | void set_free_page(void *page_array) |
将early_tbl0_page
early_tbl1_page
存入x0,x1寄存器中。early_tbl0_page
early_tbl1_page
描述如下:
1 | .early_tbl0_page: |
再通过get_pvoff x2 x3计算物理地址与虚拟地址的差值并存入x3寄存器:
1 | .macro get_pvoff, tmp, out |
该函数先将符号boot_cpu_stack_top的地址(在链接阶段已经确定是虚拟地址)存入tmp寄存器,再将boot_cpu_stack_top的物理地址存入out寄存器,最后相减存回out寄存器
将ARCH_EARLY_MAP_SIZE的值存入x2寄存器
跳转到rt_hw_mem_setup_early
函数,此时x0-3寄存去的值分别为:
将early_tbl0_page和early_tbl1_page映射为2M的页表,分别用于内核态和用户态,而early_tbl0_page
和early_tbl0_page
分别为内核态和用户态l0页表的首地址
再跳转到enable_mmu_early
函数中
enable_mmu_early
:
1 | enable_mmu_early: |
ttbr0_el1
和ttbr1_el1
中kernel_start
的地址返回后由于x30寄存器中存放的是kernel_start
地址所以会跳转到kernel_start
中执行
1 | kernel_start: |
ldr x8, =rtthread_startup
被存放了rtthread_startup
的地址,所以会跳转到rtthread_startup
中执行,接下来就是c的代码的阅读啦~pbuf 结构体:
1 | struct pbuf { |
armv8中,执行发生在4个异常级别之一,在aarch64中,异常级别决定了特权级别,类似于armv7中定义的特权级别,异常级别决定特权级别,因此在Eln执行对于特权Pln。类似地,具有比另一个更大的n值的异常级别处于更高的异常级别,一个数字比另一个小的异常级别被描述为处于较低的异常级别。
Linux驱动开发和裸机开发的区别**
Uboot是一个裸机程序,比较复杂,就是一个bootloader。作用就是用于启动Linux或其他系统,Uboot最主要的工作就是初始化DDR(Linux的运行是运行在DDR里面的),一般linux镜像zimage(uimage)+设备树(.dtb)存放在SD,EMMC,NAND,SPI FLASH等等外置存储区域。
I.MAX6ULL IO初始化流程
ARMv8(aarch64)页表建立过程详细分析_aarch64 页表-CSDN博客
【原创】(一)ARMv8 MMU及Linux页表映射 - LoyenWang - 博客园
ARMv8架构可以支持48位虚拟地址,并配置成4级页表(4K页),或者3级页表(64K页)。而本Linux系统只使用39位虚拟地址(512G内核,512G用户),配置成3级页表(4K页)或者2级页表(64K页)
用户空间的地址63:39位都置零,内核空间地址63:39都置一,虚拟地址的第63位可以用来选择TTBRx
AArch64Linux内存布局:
地址范围开始 | 地址范围结束 | 大小 | 用途 |
---|---|---|---|
0000000000000000 | 0000007fffffffff | 512GB | 用户空间 |
ffffff8000000000 | ffffffbbfffcffff | ~240GB | vmalloc区域 |
ffffffbbfffd0000 | ffffffbcfffdffff | 64KB | 守护页 |
ffffffbbfffe0000 | ffffffbcfffeffff | 64KB | PCI I/O空间 |
ffffffbbffff0000 | ffffffbcffffffff | 64KB | 守护页 |
ffffffbc00000000 | ffffffbdffffffff | 8GB | vmemmap区域 |
ffffffbe00000000 | ffffffbffbffffff | ~8GB | 守护页和未来vmemmap区域 |
ffffffbffc000000 | ffffffbfffffffff | 64MB | 模块区域 |
ffffffc000000000 | ffffffffffffffff | 256GB | 内存(保留或未分配) |
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true