1.移植串口
(1)追踪串口打印函数
《kernel/liteos_a/platform》
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)
{
...
PRINT_RELEASE("\nmain core booting up...\n");
...
(2)最终调用函数
《liteos_a\platform\uart\amba_pl011\amba_pl011.c》
VOID UartPuts(const CHAR *s, UINT32 len, BOOL isLock)
应当按照HISI这个文件中定义的函数接口进行移植形成NXPimx6ull的代码文件
《OpenharmonyFor6ull\vendor\nxp\imx6ull\driver\imx6ull-uart\uart_imx6ull.c》
->
STATIC INLINE UINTPTR uart_to_ptr(UINTPTR n)
{
(VOID)n;
return UART_REG_BASE;
}
(3)uart的基地址:此时已经启动MMU,应当为虚拟地址
《OpenharmonyFor6ull\vendor\nxp\imx6ull\board\include\uart.h》
#if (CONSOLE_UART == UART0)
#define TTY_DEVICE "/dev/uartdev-0"
#define UART_REG_BASE UART0_REG_BASE
#define NUM_HAL_INTERRUPT_UART NUM_HAL_INTERRUPT_UART0
#elif (CONSOLE_UART == UART1)
#define TTY_DEVICE "/dev/uartdev-1"
#define UART_REG_BASE UART1_REG_BASE
#define NUM_HAL_INTERRUPT_UART NUM_HAL_INTERRUPT_UART1
#elif (CONSOLE_UART == UART2)
#define TTY_DEVICE "/dev/uartdev-2"
#define UART_REG_BASE UART2_REG_BASE
#define NUM_HAL_INTERRUPT_UART NUM_HAL_INTERRUPT_UART2
#endif
《OpenharmonyFor6ull\vendor\nxp\imx6ull\board\include\asm\platform.h》
#define UART0_REG_PBASE 0x02020000
/* 建立物理地址和虚拟地址之间的映射关系函数 */
#define UART0_REG_BASE IO_DEVICE_ADDR(UART0_REG_PBASE)
#define UART1_REG_BASE IO_DEVICE_ADDR(0x12041000)
#define UART2_REG_BASE IO_DEVICE_ADDR(0x12042000)
//#define UART0_REG_PBASE 0x12040000
#define UART1_REG_PBASE 0x12041000
#define UART2_REG_PBASE 0x12042000
#if (CONSOLE_UART == UART0)
#define UART_BASE UART0_REG_BASE
#define UART0_INT_NUM NUM_HAL_INTERRUPT_UART0
#elif (CONSOLE_UART == UART1)
#define UART_BASE UART1_REG_BASE
#define UART0_INT_NUM NUM_HAL_INTERRUPT_UART1
#elif (CONSOLE_UART == UART2)
#define UART_BASE UART2_REG_BASE
#define UART0_INT_NUM NUM_HAL_INTERRUPT_UART2
#endif
(4)建立物理地址和虚拟地址的映射函数
开始移植MMU啦
2.移植MMU
虚拟地址排列顺序:
1.KERNEL_VMM_BASE:页表1
2.DDR_RAMFS_VBASE
3.LCD_FB_VBASE
4.UNCACHED_VMM_BASE:页表2
5.VMALLOC
6.PERIPH_DEVICE_BASE
7.PERIPH_CACHED
8.PERIPH_UNCACHED
PAGE_TABLE_SET SYS_MEM_BASE, UNCACHED_VMM_BASE, UNCACHED_VMM_SIZE, MMU_INITIAL_MAP_STRONGLY_ORDERED
#ifdef LOSCFG_PLATFORM_IMX6ULL
PAGE_TABLE_SET DDR_RAMFS_ADDR, DDR_RAMFS_VBASE, DDR_RAMFS_SIZE, MMU_INITIAL_MAP_DEVICE
PAGE_TABLE_SET LCD_FB_BASE, LCD_FB_VBASE, LCD_FB_SIZE, MMU_INITIAL_MAP_DEVICE
#endif
PAGE_TABLE_SET SYS_MEM_BASE, KERNEL_VMM_BASE, KERNEL_VMM_SIZE, MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_DEVICE_BASE, PERIPH_DEVICE_SIZE, MMU_INITIAL_MAP_DEVICE
PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_CACHED_BASE, PERIPH_CACHED_SIZE, MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_UNCACHED_BASE, PERIPH_UNCACHED_SIZE, MMU_INITIAL_MAP_STRONGLY_ORDERED
其中,PAGE_TABLE_SET 为宏定义,其定义在reset_vector_up.s为:
/* param0 is physical address, 物理地址
param1 virtual address, 虚拟地址
param2 is sizes, 大小
param3 is flag 标志
*/
.macro PAGE_TABLE_SET param0, param1, param2, param3
ldr r6, =\param0
ldr r7, =\param1
ldr r8, =\param2
ldr r10, =\param3
bl page_table_build
.endm
/*
* r4: page table base address
* r6: physical address
* r7: virtual address
* r8: sizes
* r10: flags
* r9 and r12 will be used as variable
*/
page_table_build:
mov r9, r6 //r9=r6:物理地址
bfc r9, #20, #12 /* r9: pa % MB */
add r8, r8, r9 //r8:末地址
add r8, r8, #(1 << 20) //
sub r8, r8, #1
/*lsr 右移指令*/
lsr r6, #20 /* r6 = physical address / MB */
lsr r7, #20 /* r7 = virtual address / MB */
lsr r8, #20 /* r8 = roundup(size, MB) */
/*r6 physAddr右移20位之后的值
r7 virtual address
r8 sizes
r10: flags
*/
page_table_build_loop:
/*lsl 左移指令,r12 = r10 | r6<<20
orr 位或指令
r12 = r10 | r6<<20
一级描述符的内容:r12 = r10存储的本段的flags | 本段实际的物理地址的基地址*/
orr r12, r10, r6, lsl #20 /* r12: flags | physAddr */
/*一级描述符的地址: r4为基地址 + r7虚拟地址的bit31~bit20 + 0b00 ,参见[liteOS-A学习笔记-2.移植串口和MMU预备知识] FIGURE 3.3*/
str r12, [r4, r7, lsl #2] /* gPgTable[l1Index] = physAddr | flags */
/* r6物理地址基址指向下一个段 */
add r6, #1 /* physAddr+ */
/* r7虚拟地址基址也指向下一个段 */
add r7, #1 /* l1Index++ */
/* r8剩余段的数量减小一个 */
subs r8, #1 /* sizes-- */
bne page_table_build_loop
bx lr
2.1 代码分析-初始化页表1:物理地址和不使用cache时的地址之间转换
// 系统内存的物理地址,系统内存的虚拟地址,系统内存的大小,内存的类型
// 0x80000000, 相当于DDR内存的大小,
PAGE_TABLE_SET SYS_MEM_BASE, UNCACHED_VMM_BASE, UNCACHED_VMM_SIZE, MMU_INITIAL_MAP_STRONGLY_ORDERED
(1)SYS_MEM_BASE:系统内存的物理地址
《OpenharmonyFor6ull\vendor\nxp\imx6ull\board\include\board.h》
(2)UNCACHED_VMM_BASE:系统内存的虚拟地址
《OpenharmonyFor6ull\kernel\liteos_a\kernel\base\include\los_vm_zone.h》
其中,KERNEL_VADDR_BASE
和KERNEL_VADDR_SIZE
《OpenharmonyFor6ull\vendor\nxp\imx6ull\board\include\board.h》
(3)UNCACHED_VMM_SIZE:系统内存的大小
《OpenharmonyFor6ull\kernel\liteos_a\kernel\base\include\los_vm_zone.h》
(4)MMU_INITIAL_MAP_STRONGLY_ORDERED:
《OpenharmonyFor6ull\kernel\liteos_a\arch\arm\arm\include\los_mmu_descriptor_v6.h》
#define MMU_INITIAL_MAP_STRONGLY_ORDERED \
(MMU_DESCRIPTOR_L1_TYPE_SECTION | \
MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED | \
MMU_DESCRIPTOR_L1_SMALL_DOMAIN_CLIENT | \
MMU_DESCRIPTOR_L1_AP_P_RW_U_NA)
宏定义,规定了内存的类型
2.2 代码分析-初始化页表2:物理地址和使用cache时的地址之间转换
// 系统内存的物理地址,系统内存的虚拟地址,系统内存的大小,内存的类型
// 0x80000000, 相当于DDR内存的大小,
PAGE_TABLE_SET SYS_MEM_BASE, KERNEL_VMM_BASE, KERNEL_VMM_SIZE, MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
2.3 代码分析-初始化页表3:外设的基地址和它的虚拟地址之间转换
PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_DEVICE_BASE, PERIPH_DEVICE_SIZE, MMU_INITIAL_MAP_DEVICE
PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_CACHED_BASE, PERIPH_CACHED_SIZE, MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_UNCACHED_BASE, PERIPH_UNCACHED_SIZE, MMU_INITIAL_MAP_STRONGLY_ORDERED
(1)PERIPH_PMM_BASE:
《OpenharmonyFor6ull\vendor\nxp\imx6ull\board\include\board.h》
/* Peripheral register address base and size */
#define PERIPH_PMM_BASE 0x00a00000
#define PERIPH_PMM_SIZE 0x02300000
(2)PERIPH_DEVICE_BASE
PERIPH_CACHED_BASE
PERIPH_UNCACHED_BASE
《OpenharmonyFor6ull\kernel\liteos_a\kernel\base\include\los_vm_zone.h》
#define VMALLOC_START (UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE)
#define VMALLOC_SIZE 0x08000000
#define PERIPH_DEVICE_BASE (VMALLOC_START + VMALLOC_SIZE)
#define PERIPH_DEVICE_SIZE PERIPH_PMM_SIZE
#define PERIPH_CACHED_BASE (PERIPH_DEVICE_BASE + PERIPH_DEVICE_SIZE)
#define PERIPH_CACHED_SIZE PERIPH_PMM_SIZE
#define PERIPH_UNCACHED_BASE (PERIPH_CACHED_BASE + PERIPH_CACHED_SIZE)
#define PERIPH_UNCACHED_SIZE PERIPH_PMM_SIZE
(3)外围物理地址和虚拟地址转换
#define IO_DEVICE_ADDR(paddr) (paddr - PERIPH_PMM_BASE + PERIPH_DEVICE_BASE)
#define IO_CACHED_ADDR(paddr) (paddr - PERIPH_PMM_BASE + PERIPH_CACHED_BASE)
#define IO_UNCACHED_ADDR(paddr) (paddr - PERIPH_PMM_BASE + PERIPH_UNCACHED_BASE)
3.启动MMU后虚拟地址和物理地址转换
OpenharmonyFor6ull\kernel\liteos_a\kernel\base\include\los_vm_zone.h
虚拟地址和物理地址之间只是起始地址有变化,目前是按照一级页表进行映射的
#define IO_DEVICE_ADDR(paddr) (paddr - PERIPH_PMM_BASE + PERIPH_DEVICE_BASE)
#define IO_CACHED_ADDR(paddr) (paddr - PERIPH_PMM_BASE + PERIPH_CACHED_BASE)
#define IO_UNCACHED_ADDR(paddr) (paddr - PERIPH_PMM_BASE + PERIPH_UNCACHED_BASE)
#define MEM_CACHED_ADDR(paddr) (paddr - DDR_MEM_ADDR + KERNEL_VMM_BASE)
#define MEM_UNCACHED_ADDR(paddr) (paddr - DDR_MEM_ADDR + UNCACHED_VMM_BASE)
#define VMM_TO_UNCACHED_ADDR(vaddr) (vaddr - KERNEL_VMM_BASE + UNCACHED_VMM_BASE)
#define UNCACHED_TO_VMM_ADDR(vaddr) (vaddr - UNCACHED_VMM_BASE + KERNEL_VMM_BASE)
#define VMM_TO_DMA_ADDR(vaddr) (vaddr - KERNEL_VMM_BASE + SYS_MEM_BASE)
#define DMA_TO_VMM_ADDR(vaddr) (vaddr - SYS_MEM_BASE + KERNEL_VMM_BASE)