HylicOS --- 内存抽象

news2025/1/11 11:17:17

HylicOS已经完成了部分硬件抽象层的工作,包括MMU的初始化并对虚拟内存到物理内存做了映射,创建了页表目录。对串口进行了初始化,实现了printk格式化打印函数,方便了日志输出和程序调试。建立了异常向量表。

现在要做的是内存管理部分。
对内存资源的管理最终要实现对内存完全地掌控:知道哪些地方有可用合法内存。能够快速找到一块想要的大小的内存,这块内存想大就大,想小就小。

为了能够掌握硬件可用的所有物理内存资源,需要对所有的物理内存资源进行描述:
考虑到移植性,每个硬件平台上的物理内存的分布都是不同的,对不同硬件平台的物理内存进行描述也必将不同,所以不能写死。
mini2440有一块64M的SDRAM,有一些地址空间映射的是设备寄存器,有些是空洞,依据这些属性对每一类内存抽象出一个结构体

typedef enum 
{
    ADRSPACE_NOT =  0,
    ADRSPACE_IO  =  1,
    ADRSPACE_SDRAM = 2,
    ADRSPACE_RAM   = 3,
    ADRSPACE_ROM   = 4,
    ADRSPACE_NORFLASH  = 5,
    ADRSPACE_NANDFLASH = 6,
}phymem_type_e;

typedef struct 
{
    phymem_type_e phymem_type;
    u32_t dev_type;
    adr_t adr_start;
    adr_t adr_end;
}phymemspce_t;

其中:
phymem_type成员指示这块物理内存的类型,dev_type是指示设备的类型
adr_start成员描述这块物理内存的起始地址,adr_end成员描述这块物理内存的终止地址。

有了这个结构体作为模版,就可以将各块物理内存创建为一个个对象,为了更好地管理这些物理内存对象,可以将他们放到一个数组中:

HAL_DEFGLOB_VARIABLE(phymemspce_t,phymemspce)[PLFM_ADRSPCE_NR] = {
{ADRSPACE_NORFLASH,0,0,0x001fffff},
{ADRSPACE_IO,0,0x08000000,0x0800000f},
{ADRSPACE_IO,0,0x10000000,0x1000000f},
{ADRSPACE_IO,0,0x19000000,0x190fffff},
{ADRSPACE_IO,0,0x20000000,0x2000000f},
{ADRSPACE_IO,0,0x28000000,0x28000007},
{ADRSPACE_IO,0,0x29000000,0x29000007},
{ADRSPACE_SDRAM,0,0x30000000,0x33ffffff},
{ADRSPACE_IO,0,0x48000000,0x48000030},
{ADRSPACE_IO,0,0x49000000,0x49000058},
{ADRSPACE_IO,0,0x4a000000,0x4a00001c},
{ADRSPACE_IO,0,0x4b000000,0x4b0000e0},
{ADRSPACE_IO,0,0x4c000000,0x4c000018},
{ADRSPACE_IO,0,0x4d000000,0x4d000060},
{ADRSPACE_IO,0,0x4e000000,0x4e00003c},
{ADRSPACE_IO,0,0x4f000000,0x4f0000a0},
{ADRSPACE_IO,0,0x50000000,0x50008028},
{ADRSPACE_IO,0,0x51000000,0x51000040},
{ADRSPACE_IO,0,0x52000000,0x5200026f},
{ADRSPACE_IO,0,0x53000000,0x53000008},
{ADRSPACE_IO,0,0x54000000,0x54000010},
{ADRSPACE_IO,0,0x55000000,0x55000012},
{ADRSPACE_IO,0,0x56000000,0x560000cc},
{ADRSPACE_IO,0,0x57000040,0x5700008b},
{ADRSPACE_IO,0,0x58000000,0x58000014},
{ADRSPACE_IO,0,0x59000000,0x59000034},
{ADRSPACE_IO,0,0x5a000000,0x5a000043},
{ADRSPACE_IO,0,0x5b000000,0x5b00001c},
{ADRSPACE_NOT,DEV_TYPE,0,0}};

这个数组的定义和初始化应该放在一个全局位置(hal_global.c中),后面很多模块都要使用到它。
对于这个HAL_DEFGLOB_VARIABLE宏,是仿UNIX美学所在。用于定义只在一个本文件定义,其他文件则为外部声明的方式
其定义在hal_global.c对应的头文件中hal_global_t.h为:

#define HAL_DEFGLOB_VARIABLE(vartype,varname) EXTERN (__attribute__((".head.text"))) vartype varname

这里EXTERN宏被定义为extern
除此之外还要再定义一个规则在hal_global.h里:

#ifndef HALGLOBAL_HEAD
#undef EXTERN
#define EXTERN
#endif

当一个模块include了hal_global_t.h和hal_global.h时,使用HAL_DEFGLOB_VARIABLE定义变量,此时有EXTERN的定义,就是外部声明。
当一个模块include了hal_global_t.h和hal_global.h前额外的#define HALGLOBAL_HEAD,此时没有EXTERN宏的定义,就是定义。

这种做法可以在一处定义变量,其他使用它的地方只做外部声明。


现在物理地址被分类且描述出来了,操作系统需要服务程序,在程序需要内存资源时给出一块内存的起始地址,所以在操作系统的设计阶段就应该将辽阔物理内存切割为一块块单元区域,在这里我们的系统每一个区域都是4MB,用一个结构体描述,保存该单元区域的起始地址和结束地址,还有这个区域内部更加细分的分区情况,更包括了细分后的分区的占用情况:

typedef struct mmapdsc
{
	list_h_t    map_list;       //list to connection every memory map describtor
	adr_t       map_phyadr;     //memory physical start address 
	adr_t       map_phyadrend;  //memory physical end   address
	u32_t       map_flg;        //used to determine next domain(memory map attribution status)
	u32_t       map_attrstatus; //map_flg=6 map_attrstatus[0]   4MB=>4MB      0=>available | 1=>busy
								//map_flg=5 map_attrstatus[1:0] 4MB=>2MB+2MB 
								//map_flg=4 map_attrstatus[3:0] 4MB=>1MB+1MB+1MB+1MB 
	spinlock_t  map_lock;
}mmapdsc_t;

从每个成员的注释中已经可以一窥究竟,以表格形式列出更加清晰:

memberfunction
map_list区域单元彼此需要链接起来,该成员作为链表节点
map_phyadr区域单元的起始物理地址
map_phyadrend区域单元的结束物理地址
map_flg决定了该块区域单元以怎样精度细分
map_attrstatus细分后区域的位图描述
map_lock保护该结构的自旋锁

现在这个结构体还只是一纸空谈,需要实际为每个区域单元分配实际物理地址,一一绑定到每个实际的4MB地址上去。需要写一个初始化函数。在此之前我们需要一个更加宏观的数据结构,将前面两种结构的信息都存储进去:
我们将这个结构整体叫做机器数据结构,由下面注释可见,核心就是
mmapdscadr, mmapdscnum以及phyadrdsc,phyadrdscnum四个成员。前俩是对每一个4MB物理内存单元的抽象和描述,后俩是对整个物理内存的描述。

typedef struct mach
{
    spinlock_t  mlock;
    list_h_t    mlist;
    adr_t       krlposramstart; //kernel position start at ram
    adr_t       krlposramend;   //kernel position end   at ram
    mmapdsc_t*  mmapdscadr;     //memory map describe start addr at ram
    uint_t      mmapdscnum;     //memory map describe number
    uint_t       phyadrdscnum;  //physical address space describer number
    phymemspce_t* phyadrdsc;  //physical address space describer start address
    // ilnedsc_t*   ilnedsc;
    uint_t       ilnedscnum;
    // intfltdsc_t* intfltdsc;  //interrupt source describer address
    //uint_t       intfltnum;     //interrupt source describer number
}mach_t;

首先需要定义一个mach_t类型的全局变量,同样是使用HAL_DEFGLOB_VARIABLE宏定义在hal_global.c中:

HAL_DEFGLOB_VARIABLE(mach_t,osmach);

对机器数据结构单独开一个C文件进行初始化与操作,machine.c被创建出来以承担这个责任:
对机器数据结构的初始化,首先是krlposramstart,这个成员用KRNL_INRAM_START赋值,指示内核在RAM中的起始位置
值为0x30000000,顺带,我们开一下HyliOS各个部分在内存的排布吧
在这里插入图片描述
橙色部分是中断向量表所在位置,也是内核起始位置,0X3000_0000
绿色部分是MMU的页表目录所在位置,0x3000_4000
红色部分是内核代码段起始位置,0x3000_8000。
__end_kernel这个宏在链接文件里定义,由链接器符号链接完之后自动计算,下面代码也引用了这个宏(记得带这个“&”)
在__end_kernel之后就是mmapdsc结构组成的数组所在了,mmapdsc的结束位置一下子不好确定。

void machine_init(void)
{
    osmach_init(&osmach);

    return;
}

void osmach_init(mach_t* initp)
{
    hal_spinlock_init(&initp->mlock);
    list_init(&initp->mlist);
    initp->krlposramstart = KRNL_INRAM_START;
    initp->krlposramend   = (adr_t) (&__end_kernel);

    // initp->mmapdsc bitmap address
    initp->mmapdscadr     = (mmapdsc_t* )(ALIGN((uint_t)(&__end_kernel),4096));
    initp->mmapdscnum     = 0;
    initp->phyadrdsc      = phymemspce;

    return;    
}

现在再来写初始化mmapdsc_t结构数组的代码


void init_mmapdsc(mach_t* mach_spedsc)
{
    phymemspce_t* pmsp = mach_spedsc->phyadrdsc;        //build in hal_global.c
    uint_t space_num   = mach_spedsc->phyadrdscnum;
    uint_t mapdsccnt   = 0;

    //init all mmapdsc
    for(uint_t i=0; i<space_num; i++)
    {
        //just sdram can be used to shared with app
        if(pmsp[i].phymem_type == ADRSPACE_SDRAM)
        {
            mapdsccnt = init_core_mmapdsc(pmsp[i].adr_start,
                                            pmsp[i].adr_end, 
                                            mach_spedsc->mmapdscadr,
                                            mapdsccnt ) ;
        }
    }
    mach_spedsc->mmapdscnum = mapdsccnt;

    //added mmapdsc thus need to modify kernel end address in ram
    mach_spedsc->krlposramend = (adr_t)( (uint_t)mach_spedsc->mmapdscadr + \ 
                                            mapdsccnt*sizeof(mach_spedsc));

}

uint_t init_core_mmapdsc(adr_t base_adr,adr_t end_adr,mmapdsc_t* mmapdsc,uint_t mapdsc_curindex)
{
    uint_t curindex = mapdsc_curindex;
    adr_t  tmpadr   = end_adr;

    for( ;base_adr < end_adr 
         ;base_adr += EACH_MAP_SIZE, curindex++)
    {
        if((base_adr+EACH_MAP_SIZE) < end_adr)
        {
            tmpadr = ( base_adr+EACH_MAP_SIZE) - 1;
        }
        else
        {
            tmpadr = end_adr;    
        }
        mmapdsc_init(mmapds[curindex], 
                        base_adr, 
                        tmpadr, 
                        0, 
                        MAP_FLAGS_VAL(0,MAPF_ACSZ_4MB,MAPF_SZ_4MB));
    }

    return curindex;
}

void mmapdsc_init(mmapdsc_t* mmp,adr_t phyadr,adr_t phyadre,u32_t attrstatus,u32_t flgs)
{
    list_init(&mmp->map_list);
    hal_spinlock_init(&mmp->mlock);
    mmp->map_phyadr = phyadr;
    mmp->map_phyadrend = phyadre;
    mmp->map_attrstatus = attrstatus;
    mmp->map_flg = flgs;

    return;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94804.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

复方一枝蒿复合磷脂/IgG二性霉素B/阿糖胞苷修饰载甲氨喋呤/酶促合成半乳糖配体脂质体制备

小编今天为大家分享的科研知识是复方一枝蒿复合磷脂/IgG二性霉素B/阿糖胞苷修饰载甲氨喋呤/酶促合成半乳糖配体脂质体&#xff0c;一起来看&#xff01; 点击输入图片描述&#xff08;最多30字&#xff09; 复方一枝蒿复合磷脂脂质体&#xff1a; 采用硫酸铵梯度法制备复方一枝…

gunicorn走私漏洞

gunicorn走私漏洞 源码&#xff1a;https://github.com/benoitc/gunicorn漏洞定位&#xff1a;https://github.com/benoitc/gunicorn/blob/20.x/gunicorn/http/message.py#142 漏洞分析 只要header里面存在Sec-Websocket-Key1 那么就将content_length强制赋值为8 比较简单直接…

【java】java JSR 269 自定义注解实战 Lombok @Data注解

1.概述 本节会演示一个实际的例子,使用JSR 269 API为类中的字段自动生成get、set 方法。首先定义一个自定义注解类Data,如下所示。 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import

智能工业之数据采集

现状 工业物联网飞速发展&#xff0c;但是相对于实时IT技术还是明显滞后的。个人理解&#xff0c;有两点原因&#xff1a;一是因为涉及的知识面也比较广&#xff0c;工业物联网开发成本比较高&#xff0c;不像做一个纯软件的管理系统&#xff0c;坐在电脑前借助开源框架就能完成…

你好,Ultrachess 里程碑更新了。

Cartesi Labs 资助的完全去中心化国际象棋项目即将来到你的面前。在10月&#xff0c;我们宣布了第一个由Cartesi Rollup 技术支持的完全链上国际象棋应用程序Ultrachess。Ultrachess允许用户将真正的价值放在赌注上&#xff0c;并在下棋时考虑的不仅仅是他们的隐藏分值。此外&…

Java中的StringBuilder类

目录 一、介绍 二、StringBuilder类的体系图 三、StringBuilder的常用方法 四、String、StringBuffer和StringBuilder比较 1、效率比较 2、如何选择&#xff1f; 一、介绍 StringBuilder也是lang包中的类&#xff0c;即java.lang.StringBuilder类。它也是一个可变的字符序…

设计模式原则-三-依赖倒转原则

设计模式原则---依赖倒转原则依赖倒转原则一 官方定义基本介绍二 案例演示普通方式实现**解决方案****案例分析****案例总结**依赖倒转原则方式实现**解决方案**案例分析**案例总结**注意事项&细节三 依赖关系传递方式一、通过接口传递二、通过构造方法传递三、通过set()方…

原来 Android 的 R 文件里还有这么多道道

前言 nonTransitiveRClass&#xff1a;非传递性 R 类的属性&#xff0c;在 gradle.properties 文件里使用。 不少开发者可能听过它&#xff0c;但了解可能仅限于是对 R 文件做了优化&#xff0c;甚至以为它可以解决资源冲突&#xff01;但它到底做了什么优化、能否解决资源冲突…

Manacher算法

0、概括 Manacher算法用于求解字符串中最长回文子串问题。 Manacher算法的核心&#xff1a; 理解回文半径数组&#xff1b;理解所有中心的回文最右边界 R&#xff0c;和取得 R 时的中心点 C&#xff1b;理解 L...(i)...C...(i)...R 的结构&#xff0c;以及根据 i′ii′ 回文长…

C-RNN-GAN:具有对抗训练的连续循环神经网络2016--生成音乐

C-RNN-GAN: Continuous recurrent neural networks with adversarial training 2016 Abstract 生成对抗网络已被提出作为一种有效训练深度生成神经网络的方法。我们提出了一种生成对抗模型&#xff0c;它适用于连续的序列数据&#xff0c;并通过在古典音乐集合上训练它来应用它…

计算机毕设Python+Vue校园学生体温管理系统(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

相见恨晚,Git这些功能太好用了

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store 作为一名开发者&#xff0c;想必绝大多数同学都无法绕开Git。 作为一款工具&#xff0c;我认为它和word、powerpoint、Excel这些办公工具一样。 对于一部分同学&#xff0c;会一些基本的用法&#x…

【经验帖】项目经理的核心价值:以目标为导向做正确的事

项目经理小李的年终汇报心路历程&#xff08;心情犹如坐过山车&#xff0c;起起落落最后一蹶不振。&#xff09; 汇报前&#xff1a; 终于到年终汇报的日子了&#xff0c;毕竟我负责的项目任务从来没有延期过&#xff0c;都是按时完成&#xff0c;这次肯定得加薪了&#xff01…

[附源码]Node.js计算机毕业设计公租房管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

module命名空间

为什么要有namespaced命名空间&#xff1f; 默认情况下&#xff0c;模块内部的action、mutation和getter都是在全局命名空间。 假设两个modules内部有同名的action、mutation和getter&#xff0c;则vuex会报错。 namespaced作用&#xff1a;保证模块内部的高封闭性&#xff0c;…

021 | 阴离子诱导的系列双核镝配合物的合成及磁性质 | 大学生创新训练项目申请书 | 极致技术工厂

研究目的 近十几年来&#xff0c;随着科技的飞速发展&#xff0c;单分子磁体材料涉及的应用领域越来越宽广。众所周知&#xff0c;单分子磁体材料作为信息存储的基础对信息产业的发展具有一定的意义。此外&#xff0c;单分子磁体在超高密度储存、自旋电子器件、量子计算机等领域…

旅游住宿网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 网站前台&#xff1a;网站介绍、帮助信息、旅游资讯。景点信息、酒店信息 管理员功能&#xff1a; 1、管理网站介绍、帮…

day22【代码随想录】在每个树行中找最大值、填充每个节点的下一个右侧节点指针、二叉树的最大深度、二叉树的最小深度

文章目录前言一、在每个树行中找最大值&#xff08;力扣515&#xff09;二、填充每个节点的下一个右侧节点指针&#xff08;力扣116&#xff09;三、二叉树的最大深度&#xff08;力扣104&#xff09;1、非递归求解2、递归求解四、 二叉树的最小深度&#xff08;力扣111&#x…

【前端开发学习】4.JavaScript

文章目录1 JavaScript1.1 代码位置1.2 存在形式1.3 注释1.4 变量1.5 字符串类型案例&#xff1a;走马灯1.5 数组案例&#xff1a;动态数据1.6 对象&#xff08;字典&#xff09;案例&#xff1a;动态表格1.7 条件语句1.8 函数2 DOM2.1 事件绑定1 JavaScript 一门编程语言&…

第二证券|主力加仓电子、电气设备等行业 北向资金连续2日净流入

沪深两市股市涨跌互现&#xff0c;上证指数早盘震动下探&#xff0c;午后一度回升&#xff0c;尾盘再度回落&#xff1b;深证成指早盘探底回升&#xff0c;午后震动上扬&#xff0c;尾盘有所回落&#xff1b;创业板指早盘窄幅震动&#xff0c;午后震动上扬&#xff1b;科创50指…