提交 30f7789e 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

对链接脚本注解

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 2bac2a79
......@@ -974,22 +974,22 @@ STATIC VOID OsSetKSectionAttr(UINTPTR virtAddr, BOOL uncached)
UINTPTR ramDataStart = (UINTPTR)&__ram_data_start + offset;
UINTPTR bssEnd = (UINTPTR)&__bss_end + offset;
UINT32 bssEndBoundary = ROUNDUP(bssEnd, MB);
LosArchMmuInitMapping mmuKernelMappings[] = {
{
LosArchMmuInitMapping mmuKernelMappings[] = {//初始化映射关系
{ //映射代码区
.phys = SYS_MEM_BASE + textStart - virtAddr,
.virt = textStart,//内核代码区
.size = ROUNDUP(textEnd - textStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),//代码区大小
.flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE,//代码段只读,可执行
.name = "kernel_text"
},
{
{ //映射只读数据
.phys = SYS_MEM_BASE + rodataStart - virtAddr,
.virt = rodataStart,//内核常量区
.size = ROUNDUP(rodataEnd - rodataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),//4K对齐
.flags = VM_MAP_REGION_FLAG_PERM_READ,//常量段只读
.name = "kernel_rodata"
},
{
{ //映射全局未初始化区
.phys = SYS_MEM_BASE + ramDataStart - virtAddr,
.virt = ramDataStart,
.size = ROUNDUP(bssEndBoundary - ramDataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),
......
......@@ -139,7 +139,7 @@ reset_vector: //鸿蒙开机代码
#endif
/*当内核被加载到内存中时,它的起始地址就叫做加载地址,因为内核是被uboot加载的,uboot中对mmu页表不会做太复杂的映射,
一般也就是一一映射,也就是物理地址和虚拟地址值是一样的,所以可以认为内核加载地址值是物理地址。*/
MOV r3, #0x40000000 //内存基地址 KERNEL_VADDR_BASE
MOV r3, #0x40000000 //指定内核运行基地址 KERNEL_VADDR_BASE,也就是说将内核镜像文件放到这个位置.
VMSR FPEXC, r3 //VMRS/VMSR ARM寄存器与NEONVFP系统寄存器之间传输内容
/* r11: delta of physical address and virtual address | 内核运行虚拟地址和物理地址之间的差值 */
adr r11, pa_va_offset //获取pa_va_offset变量的当前运行地址,由于这时候mmu已经被关闭,所以这个值就表示pa_va_offset变量的物理地址
......@@ -251,7 +251,7 @@ warm_reset://热启动
cmp r12, #0 //判断当前cpu是不是主核,如果是主核,则执行bss段清零,如果是从核则不需要执行bbs段清零
bne cpu_start //不等于 跳到从核处理
clear_bss: //bss段清零
clear_bss: //主核时对 .bss段清零
ldr r0, =__bss_start
ldr r2, =__bss_end
mov r1, #0
......
......@@ -215,6 +215,17 @@ STATIC UINT32 InitPthreadData(pthread_t threadID, pthread_attr_t *userAttr,
return ret;
}
/*!
* @brief pthread_create
* 创建线程
* @param arg 传递给线程入口函数的参数
* @param attr 指向线程属性的指针,如果使用 NULL,则使用默认的线程属性
* @param startRoutine 线程入口函数地址
* @param thread 指向线程句柄 (线程标识符) 的指针,不能为 NULL
* @return
*
* @see
*/
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*startRoutine)(void *), void *arg)
{
......@@ -222,7 +233,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
UINT32 ret;
CHAR name[PTHREAD_DATA_NAME_MAX] = {0};
STATIC UINT16 pthreadNumber = 1;
TSK_INIT_PARAM_S taskInitParam = {0};
TSK_INIT_PARAM_S taskInitParam = {0};//posix线程对标鸿蒙内核的任务
UINT32 taskHandle;
_pthread_data *self = pthread_get_self_data();
......@@ -413,6 +424,8 @@ int pthread_join(pthread_t thread, void **retVal)
/*
* Set the detachstate of the thread to "detached". The thread then does not
* need to be joined and its resources will be freed when it exits.
* 调用此函数,如果 pthread 线程没有结束,则将 thread 线程属性的分离状态设置为 detached;
* 当 thread 线程已经结束时,系统将回收 pthread 线程占用的资源。
*/
int pthread_detach(pthread_t thread)
{
......
......@@ -137,7 +137,16 @@ int pthread_cond_destroy(pthread_cond_t *cond)
cond->mutex = NULL;
return ENOERR;
}
///初始化条件变量
/*!
* @brief pthread_cond_init 初始化条件变量
*
* @param attr 指向条件变量属性的指针,若为 NULL 则使用默认属性值
* @param cond 条件变量句柄,不能为 NULL
* @return
*
* @see
*/
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
int ret = ENOERR;
......@@ -199,7 +208,7 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
return ret;
}
///解除被阻塞的线程
///解除被阻塞的线程/发送满足条件信号量
int pthread_cond_signal(pthread_cond_t *cond)
{
int ret = ENOERR;
......@@ -267,7 +276,18 @@ STATIC INT32 ProcessReturnVal(pthread_cond_t *cond, INT32 val)
}
return ret;
}
///等待条件 在指定的时间之前阻塞,函数会一直阻塞,直到该条件获得信号,或者最后一个参数所指定的时间已过为止。
/*!
* @brief pthread_cond_timedwait
* 等待条件 在指定的时间之前阻塞,函数会一直阻塞,直到该条件获得信号,或者最后一个参数所指定的时间已过为止。
* @param absTime 指定的等待时间,单位是操作系统时钟节拍(OS Tick)
* @param cond 条件变量句柄,不能为 NULL
* @param mutex 指向互斥锁控制块的指针,不能为 NULL
* @return
* 此函数和 pthread_cond_wait() 函数唯一的差别在于,如果条件变量不可用,线程将被阻塞 abstime 时长,
* 超时后函数将直接返回 ETIMEDOUT 错误码,线程将会被唤醒进入就绪态。
* @see
*/
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *absTime)
{
......@@ -318,7 +338,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
pthread_testcancel();
return ret;
}
///基于条件变量阻塞,阻塞的线程可以通过 pthread_cond_signal() 或 pthread_cond_broadcast() 唤醒
///阻塞方式获取条件变量,阻塞的线程可以通过 pthread_cond_signal() 或 pthread_cond_broadcast() 唤醒
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
int ret;
......
......@@ -457,10 +457,10 @@ STATIC INLINE User *OsCurrUserGet(VOID)
#define OS_PROCESS_INFO_ALL 1
#define OS_PROCESS_DEFAULT_UMASK 0022 ///< 系统默认的用户掩码(umask),大多数的Linux系统的默认掩码为022。
//用户掩码的作用是用户在创建文件时从文件的默认权限中去除掩码中的权限。所以文件创建之后的权限实际为:创建文件的权限为:0666-0022=0644。创建文件夹的权限为:0777-0022=0755
extern UINTPTR __user_init_entry; ///< 第一个用户态任务的入口地址 查看 LITE_USER_SEC_ENTRY
extern UINTPTR __user_init_bss; ///< 查看 LITE_USER_SEC_BSS
extern UINTPTR __user_init_end; ///< 用户空间结束虚拟地址
extern UINTPTR __user_init_load_addr;///< 用户空间加载地址
extern UINTPTR __user_init_entry; ///< 第一个用户态进程(init)的入口地址 查看 LITE_USER_SEC_ENTRY
extern UINTPTR __user_init_bss; ///< 查看 LITE_USER_SEC_BSS ,赋值由liteos.ld完成
extern UINTPTR __user_init_end; ///< init 进程的用户空间初始化结束地址
extern UINTPTR __user_init_load_addr;///< init进程的加载地址
extern UINT32 OsSystemProcessCreate(VOID);
extern VOID OsProcessCBRecycleToFree(VOID);
extern VOID OsProcessResourcesToFree(LosProcessCB *processCB);
......
......@@ -48,7 +48,7 @@ extern "C" {
#endif /* __cplusplus */
#define OS_KHEAP_BLOCK_SIZE (512 * 1024UL) ///< 内核空间 堆内存部分大小, 512K
//记录 MMU 映射关系
typedef struct ArchMmuInitMapping {
PADDR_T phys;///< 物理地址
VADDR_T virt;///< 虚拟地址
......
/*!
* @file los_vm_common.h
* @brief
* @link
@verbatim
@note_pic
鸿蒙虚拟内存-用户空间图 从 USER_ASPACE_BASE 至 USER_ASPACE_TOP_MAX
鸿蒙源码分析系列篇: https://blog.csdn.net/kuangyufei
https://my.oschina.net/u/3751245
| /\ |
| || |
|---------------------------|内核空间结束位置KERNEL_ASPACE_BASE + KERNEL_ASPACE_SIZE
| |
| 内核空间 |
| |
| |
|---------------------------|内核空间开始位置 KERNEL_ASPACE_BASE
| |
| 16M 预留 |
|---------------------------|用户空间栈顶 USER_ASPACE_TOP_MAX = USER_ASPACE_BASE + USER_ASPACE_SIZE
| |
| stack区 自上而下 |
| |
| || |
| || |
| || |
| \/ |
| |
|---------------------------|映射区结束位置 USER_MAP_BASE + USER_MAP_SIZE
| 虚拟地址-物理地址映 射区 |
| |
|---------------------------|映射区开始位置 USER_MAP_BASE = (USER_ASPACE_TOP_MAX >> 1)
| |
| |
| /\ |
| || |
| || |
| || |
| |
| heap 自下而上 |
| |
|---------------------------|用户空间堆区开始位置 USER_HEAP_BASE = USER_ASPACE_TOP_MAX >> 2
| |
| .bss |
| .data |
| .text |
|---------------------------|用户空间开始位置 USER_ASPACE_BASE = 0x01000000UL
| |
| 16M预留 |
|---------------------------|虚拟内存开始位置 0x00000000
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-30
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -43,63 +100,10 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/**
* @file los_vm_common.h
* @verbatim
@note_pic
鸿蒙虚拟内存-用户空间图 从 USER_ASPACE_BASE 至 USER_ASPACE_TOP_MAX
鸿蒙源码分析系列篇: https://blog.csdn.net/kuangyufei
https://my.oschina.net/u/3751245
| /\ |
| || |
|---------------------------|内核空间结束位置KERNEL_ASPACE_BASE + KERNEL_ASPACE_SIZE
| |
| 内核空间 |
| |
| |
|---------------------------|内核空间开始位置 KERNEL_ASPACE_BASE
| |
| 16M 预留 |
|---------------------------|用户空间栈顶 USER_ASPACE_TOP_MAX = USER_ASPACE_BASE + USER_ASPACE_SIZE
| |
| stack区 自上而下 |
| |
| || |
| || |
| || |
| \/ |
| |
|---------------------------|映射区结束位置 USER_MAP_BASE + USER_MAP_SIZE
| 虚拟地址-物理地址映射区 |
| |
|---------------------------|映射区开始位置 USER_MAP_BASE = (USER_ASPACE_TOP_MAX >> 1)
| |
| |
| /\ |
| || |
| || |
| || |
| |
| heap 自下而上 |
| |
|---------------------------|用户空间堆区开始位置 USER_HEAP_BASE = USER_ASPACE_TOP_MAX >> 2
| |
| .bss |
| .data |
| .text |
|---------------------------|用户空间开始位置 USER_ASPACE_BASE = 0x01000000UL
| |
| 16M预留 |
|---------------------------|虚拟内存开始位置 0x00000000
* @endverbatim
* @brief
*/
/* user address space, defaults to below kernel space with a 16MB guard gap on either side */
#ifndef USER_ASPACE_BASE ///< 用户地址空间,默认为低于内核空间,两侧各有16MB的保护间隙
#define USER_ASPACE_BASE ((vaddr_t)0x01000000UL) ///< 用户空间基地址 从16M位置开始
#define USER_ASPACE_BASE ((vaddr_t)0x01000000UL) ///< 用户空间基地址 从16M位置开始 user_ram : ORIGIN = 0x1000000, LENGTH = 0x100000
#endif
#ifndef USER_ASPACE_SIZE
#define USER_ASPACE_SIZE ((vaddr_t)KERNEL_ASPACE_BASE - USER_ASPACE_BASE - 0x01000000UL)///< 用户空间 < 内核空间 2个16M
......@@ -125,10 +129,11 @@ extern "C" {
* @verbatim
圆整通常被理解为为满足某种要求而进行的数据修正。按照修正后的数据在数值上是否比原数据大,
又可分为向上圆整和向下圆整。它们很像对模拟信号进行采样,对一定范围的数据向一个固定的数据靠拢。
举例:ROUNDUP(7,4) = 8 ,ROUNDUP(8,4) = 8 ,ROUNDUP(9,4) = 12
举例理解:
ROUNDUP(7,4) = 8 ,ROUNDUP(8,4) = 8 ,ROUNDUP(9,4) = 12
ROUNDDOWN(7,4) = 4 ,ROUNDDOWN(8,4) = 8 ,ROUNDDOWN(9,4) = 8
ROUNDOFFSET(7,4) = 3 ,ROUNDOFFSET(8,4) = 0 ,ROUNDOFFSET(9,4) = 1
发现规律看明白了吗?
* @endverbatim
*/
#define ROUNDUP(a, b) (((a) + ((b) - 1)) & ~((b) - 1)) ///< 向上圆整
......@@ -139,7 +144,7 @@ extern "C" {
#define IS_ALIGNED(a, b) (!(((UINTPTR)(a)) & (((UINTPTR)(b)) - 1)))///< 是否按指定的参数对齐
#define IS_PAGE_ALIGNED(x) IS_ALIGNED(x, PAGE_SIZE) ///< 是否按页大小对齐 4K
#define IS_SECTION_ALIGNED(x) IS_ALIGNED(x, SECTION_SIZE)///< 是否按段大小对齐
//虚拟内存的异常提示
#define LOS_ERRNO_VM_NO_ERROR (0)
#define LOS_ERRNO_VM_GENERIC (-1)
#define LOS_ERRNO_VM_NOT_FOUND (-2)
......
......@@ -4,7 +4,7 @@
* @link
@verbatim
@note_pic
鸿蒙地址空间全景图 从 0x00000000U 至 0xFFFFFFFFU ,外设和主存采用统一编址方式
虚拟地址空间全景图 从 0x00000000U 至 0xFFFFFFFFU ,外设和主存采用统一编址方式
鸿蒙源码分析系列篇: https://blog.csdn.net/kuangyufei
https://my.oschina.net/u/3751245
......@@ -19,19 +19,20 @@
| PERIPH_PMM_SIZE |
+----------------------------+ 外围设备基地址 PERIPH_DEVICE_BASE
| Vmalloc段 |
| kernel heap |
| kernel heap |内核堆空间
| 128M |
| 映射区 |
+----------------------------+ 内核动态分配开始地址 VMALLOC_START
| DDR_MEM_SIZE |
| Uncached段 |
+----------------------------+ 未缓存虚拟空间基地址 UNCACHED_VMM_BASE
+----------------------------+ 未缓存虚拟空间基地址 UNCACHED_VMM_BASE = KERNEL_VMM_BASE + KERNEL_VMM_SIZE
| 内核虚拟空间 |
| KERNEL_VMM_SIZE |
| .bss |
| .rodata |
| .text |
| 映射区 |
| mmu table 临时页表 |临时页表的作用详见开机阶段汇编代码注释
| .bss |Block Started by Symbol : 未初始化的全局变量,内核映射页表所在区 g_firstPageTable,这个表在内核启动后更新
| .data 可读写数据区 |
| .rodata 只读数据区 |
| .text 代码区 |
| vectors 中断向量表 |
+----------------------------+ 内核空间开始地址 KERNEL_ASPACE_BASE = KERNEL_VMM_BASE
| 16M预留区 |
+----------------------------+ 用户空间栈顶 USER_ASPACE_TOP_MAX = USER_ASPACE_BASE + USER_ASPACE_SIZE
......@@ -48,21 +49,28 @@
+----------------------------+ 0x00000000U
以下定义 可见于 ..\vendor\hi3516dv300\config\board\include\board.h
#ifdef LOSCFG_KERNEL_MMU
#ifdef LOSCFG_TEE_ENABLE
#define KERNEL_VADDR_BASE 0x41000000
#else
#define KERNEL_VADDR_BASE 0x40000000
#endif
#else
#define KERNEL_VADDR_BASE DDR_MEM_ADDR
#endif
#define KERNEL_VADDR_SIZE DDR_MEM_SIZE
#define SYS_MEM_BASE DDR_MEM_ADDR
#define SYS_MEM_END (SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT)
在liteos_a中, KERNEL_VADDR_BASE 是一个很常用的地址, 可以叫内核的运行起始地址
内核的运行地址就是内核设计者希望内核运行时在内存中的位置,这个地址在内核源码中有地方可以配置,
并且链接脚本里也会用到这个地址,编译代码时所用到的跟地址相关的值都是以内核运行基址为基础进行计算的。
在liteos_a中,内核运行基址是在各个板子的board.h中配置的
#define EXC_INTERACT_MEM_SIZE 0x100000
#ifdef LOSCFG_KERNEL_MMU
#ifdef LOSCFG_TEE_ENABLE
#define KERNEL_VADDR_BASE 0x41000000
#else
#define KERNEL_VADDR_BASE 0x40000000
#endif
#else
#define KERNEL_VADDR_BASE DDR_MEM_ADDR
#endif
#define KERNEL_VADDR_SIZE DDR_MEM_SIZE
#define SYS_MEM_BASE DDR_MEM_ADDR
#define SYS_MEM_END (SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT)
#define EXC_INTERACT_MEM_SIZE 0x100000
内核空间范围: 0x40000000 ~ 0xFFFFFFFF
用户空间氛围: 0x00000000 ~ 0x3FFFFFFF
......@@ -123,19 +131,20 @@ extern "C" {
#endif /* __cplusplus */
#ifdef LOSCFG_KERNEL_MMU
#ifdef LOSCFG_KERNEL_MMU //
#ifdef LOSCFG_TEE_ENABLE
#define KERNEL_VADDR_BASE 0x41000000
#else
#define KERNEL_VADDR_BASE 0x40000000
#endif
#else
#define KERNEL_VADDR_BASE DDR_MEM_ADDR ///< 主存基地址 Double Data Rate SDRAM
#else //没有MMU时,内核运行基址 = 内存的基地址,因为没有了MMU,所以也没有了虚拟内存和物理内存的说法,统一就是物理内存.
#define KERNEL_VADDR_BASE DDR_MEM_ADDR ///< 内核运行基址 等于内存( Double Data Rate SDRAM)基地址
#endif
#define KERNEL_VADDR_SIZE DDR_MEM_SIZE ///< 主存大小
#define KERNEL_VADDR_SIZE DDR_MEM_SIZE ///< 真实主存的大小
#define SYS_MEM_BASE DDR_MEM_ADDR ///< 物理内存基地址
#define SYS_MEM_END (SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT) ///< 物理内存大小
#define SYS_MEM_END (SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT) ///< 物理内存结束地址
#define _U32_C(X) X##U
......
......@@ -46,10 +46,10 @@ extern "C" {
#endif /* __cplusplus */
/**
* @ingroup los_config
* int stack start addr
* @ingroup los_config
* int stack start addr | 值在链接时赋予,详见liteos.ld文件
*/
extern CHAR __int_stack_start; ///< 运行系统函数栈的开始地址
extern CHAR __int_stack_start; ///< 运行系统函数栈的开始地址 值来自于 liteos.ld中的 __int_stack_start = .;
extern CHAR __rodata_start; ///< ROM开始地址 只读
extern CHAR __rodata_end; ///< ROM结束地址
extern CHAR __bss_start; ///< bss开始地址 __attribute__((section(".__bss_start")));
......
......@@ -500,18 +500,18 @@ typedef struct {//用户态栈信息,(按递减满栈方式注解)
* Information of specified parameters passed in during task creation.
*/
typedef struct tagTskInitParam {//Task的初始化参数
TSK_ENTRY_FUNC pfnTaskEntry; /**< Task entrance function */ //任务的入口函数
UINT16 usTaskPrio; /**< Task priority */ //任务优先级
UINT16 policy; /**< Task policy */ //任务调度方式
UINTPTR auwArgs[4]; /**< Task parameters, of which the maximum number is four */ //入口函数的参数,最多四个
UINT32 uwStackSize; /**< Task stack size */ //内核栈大小
CHAR *pcName; /**< Task name */ //任务名称
TSK_ENTRY_FUNC pfnTaskEntry; /**< Task entrance function | 任务的入口函数*/
UINT16 usTaskPrio; /**< Task priority | 任务优先级*/
UINT16 policy; /**< Task policy | 任务调度方式*/
UINTPTR auwArgs[4]; /**< Task parameters, of which the maximum number is four | 入口函数的参数,最多四个*/
UINT32 uwStackSize; /**< Task stack size | 内核栈大小*/
CHAR *pcName; /**< Task name | 任务名称*/
#ifdef LOSCFG_KERNEL_SMP
UINT16 usCpuAffiMask; /**< Task cpu affinity mask */ //任务cpu亲和力掩码
UINT16 usCpuAffiMask; /**< Task cpu affinity mask | 任务cpu亲和力掩码 */
#endif
UINT32 uwResved; /**< It is automatically deleted if set to LOS_TASK_STATUS_DETACHED.
It is unable to be deleted if set to 0. */ //如果设置为LOS_TASK_STATUS_DETACHED,则自动删除。如果设置为0,则无法删除
UINT16 consoleID; /**< The console id of task belongs */ //任务的控制台id所属
It is unable to be deleted if set to 0. | 如果设置为LOS_TASK_STATUS_DETACHED,则自动删除。如果设置为0,则无法删除*/
UINT16 consoleID; /**< The console id of task belongs | 任务的控制台id所属*/
UINT32 processID; ///< 进程ID
UserTaskParam userParam; ///< 任务用户态运行时栈参数
} TSK_INIT_PARAM_S;
......
......@@ -57,13 +57,30 @@ SECTIONS
USER_INIT_VM_START = 0x1000000;
***********************************************/
#define TEXT_BASE KERNEL_VADDR_BASE
#define TEXT_BASE KERNEL_VADDR_BASE //代码区为内核起始地址
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
/*
https://www.jianshu.com/p/42823b3b7c8e
MEMORY:内存布局,描述板上的存储器位置
语法为
NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2
NAME :存储区域的名字。(自己可以随意命名)
ATTR :定义该存储区域的属性。ATTR属性内可以出现以下7 个字符:
R 只读section
W /section
X 可执行section
A 可分配的section
I 初始化了的section
L I
! 不满足该字符之后的任何一个属性的section
ORIGIN :关键字,区域的开始地址,可简写成org o
LENGTH :关键字,区域的大小,可简写成len l
*/
MEMORY
{
{ //ram,sram为存储区域的名字,可以随意取
ram : ORIGIN = KERNEL_VADDR_BASE, LENGTH = KERNEL_VADDR_SIZE
sram : ORIGIN = 0x40000000, LENGTH = 0x1000
user_ram : ORIGIN = 0x1000000, LENGTH = 0x100000
......
......@@ -647,6 +647,19 @@ static int NfsMount(const char *serverIpAndPath, const char *mountPath,
}
#endif
/*!
* @brief SysMount 挂载文件系统
* 挂载是指将一个存储设备挂接到一个已存在的路径上。我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的路径上,
* 然后通过这个路径来访问存储设备。如果只有一个存储设备,则可以直接挂载到根目录 / 上,变成根文件系统
* @param data 特定文件系统的私有数据
* @param filesystemtype 挂载的文件系统类型
* @param mountflags 读写标志位
* @param source 已经格式化的块设备名称
* @param target 挂载路径,即挂载点
* @return
*
* @see
*/
int SysMount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags,
const void *data)
{
......@@ -714,7 +727,7 @@ OUT:
}
return ret;
}
///卸载文件系统
///卸载文件系统,当某个文件系统不需要再使用了,那么可以将它卸载掉。
int SysUmount(const char *target)
{
int ret;
......@@ -1095,7 +1108,27 @@ static int SelectParamCheckCopy(fd_set *readfds, fd_set *writefds, fd_set *excep
return 0;
}
///系统调用|文件系统|select .鸿蒙liteos目前不支持epoll方式
/*!
* @brief SysSelect 系统调用|文件系统|select .鸿蒙liteos目前也支持epoll方式
*
* @param exceptfds 文件集将监视文件集中的任何文件是否发生错误,可用于其他的用途,
* 例如,监视带外数据OOB,带外数据使用MSG_OOB标志发送到套接字上。当select函数返回的时候,
* exceptfds将清除其中的其他文件描述符,只留下标记有OOB数据的文件描述符。
* @param nfds select监视的文件句柄数,一般设为要监视各文件中的最大文件描述符值加1。
* @param readfds 文件描述符集合监视文件集中的任何文件是否有数据可读,当select函数返回的时候,
* readfds将清除其中不可读的文件描述符,只留下可读的文件描述符。
* @param timeout 参数是一个指向 struct timeval 类型的指针,它可以使 select()在等待 timeout 时间后
* 若没有文件描述符准备好则返回。其timeval结构用于指定这段时间的秒数和微秒数。它可以使select处于三种状态:
* (1) 若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
* (2) 若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
* (3) timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。
* @param writefds 文件描述符集合监视文件集中的任何文件是否有数据可写,当select函数返回的时候,
* writefds将清除其中不可写的文件描述符,只留下可写的文件描述符。
* @return
*
* @see
*/
int SysSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
int ret;
......@@ -1500,7 +1533,19 @@ OUT_FREE:
(void)LOS_MemFree(OS_SYS_MEM_ADDR, iovRet);
return ret;
}
///I/O多路转换
/*!
* @brief SysPoll I/O多路转换
*
* @param fds fds是一个struct pollfd类型的数组,用于存放需要检测其状态的socket描述符,并且调用poll函数之后fds数组不会被清空;
* 一个pollfd结构体表示一个被监视的文件描述符,通过传递fds指示 poll() 监视多个文件描述符。
* @param nfds 记录数组fds中描述符的总数量。
* @param timeout 指定等待的毫秒数,无论 I/O 是否准备好,poll() 都会返回,和select函数是类似的。
* @return 函数返回fds集合中就绪的读、写,或出错的描述符数量,返回0表示超时,返回-1表示出错;
* poll改变了文件描述符集合的描述方式,使用了pollfd结构而不是select的fd_set结构,使得poll支持的文件描述符集合限制远大于select的1024。
* 这也是和select不同的地方。
* @see
*/
int SysPoll(struct pollfd *fds, nfds_t nfds, int timeout)
{
int ret;
......
ENTRY(reset_vector)
INCLUDE board.ld
// GNU 链接脚本语法 https://sourceware.org/binutils/docs/ld/LD-Index.html
ENTRY(reset_vector) /*指定入口地址*/
INCLUDE board.ld // > ram 指的是要大于 ram这个地址, ram在board.ld中定义
/* 这是脚本中最重要的命令了,所有的LD脚本都会有这个命令,用来指定如何将输入文件映射到输出文件等等 */
SECTIONS
{
_start = .;
.set_sysinit_set : {
__start_set_sysinit_set = ABSOLUTE(.);
KEEP (*(.set_sysinit_set))
KEEP (*(.set_sysinit_set))//在连接命令行内使用了选项–gc-sections后,连接器可能将某些它认为没用的section过滤掉,此时就有必要强制连接器保留一些特定的 section,可用KEEP()关键字达此目的。
__stop_set_sysinit_set = ABSOLUTE(.);
} > ram
......@@ -126,34 +128,34 @@ SECTIONS
__ram_data_end = .;
} > ram
.user_init USER_INIT_VM_START : ALIGN(0x1000) {
.user_init USER_INIT_VM_START : ALIGN(0x1000) {//开始地址设为 USER_INIT_VM_START
. = ALIGN(0x4);
__user_init_load_addr = LOADADDR(.user_init);
__user_init_entry = .;
__user_init_load_addr = LOADADDR(.user_init);//应用程序的加载地址
__user_init_entry = .;//应用程序的入口地址
KEEP(libuserinit.O (.user.entry))
KEEP(libuserinit.O (.user.text))
KEEP(libuserinit.O (.user.rodata))
. = ALIGN(0X4);
__user_init_data = .;
__user_init_data = .;//设置数据段开始位置 __user_init_data
KEEP(libuserinit.O (.user.data))
. = ALIGN(0X4);
__user_init_bss = .;
__user_init_bss = .;//将当前位置给__user_init_bss
KEEP(libuserinit.O (.user.bss))
. = ALIGN(0x1000);
__user_init_end = .;
__user_init_end = .;/
} > user_ram AT > ram
__user_init_size = __user_init_end - __user_init_entry;
/* unintialized data (in same segment as writable data) */
/* unintialized data (in same segment as writable data)*/
.bss : {
. = ALIGN(0x800);
__int_stack_start = .;
. = ALIGN(0x800); //当前位置按 0x800对齐
__int_stack_start = .; //将当前位置给__int_stack_start
*(.int_stack);
. = ALIGN(0x4);
KEEP(*(.bss.prebss.*))
. = ALIGN(0x8);
__bss_start = .;
__bss_start = .; //将当前位置给__bss_start,将所有的目标*(.bss .bss.*) .. 链接到 .bss中
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
......
git add -A
git commit -m ' 对开机汇编代码详细注解
git commit -m ' 对链接脚本注解
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册