12.1位视图的创建和对内存的分配

12.1位视图的创建和对内存的分配

对于内存管理要处理下列问题

位视图(页为单位)解决的是内存的分配问题

位视图的数据结构(结构体)

//D:\code\x86\code\start\start\source\kernel\include\tools\bitmap.h
#ifndef BITMAP_H
#define BITMAP_H

#include "comm/types.h"

/**
 * @brief 位图数据结构
 */
typedef struct _bitmap_g {
    int bit_count;              // 位的数据,位数量
    uint8_t * bits;             // 位空间,字节数组,靠外面传进来
}bitmap_t;

void bitmap_init (bitmap_t * bitmap, uint8_t * bits, int count, int init_bit); //初始化,init_bit表示初始化是全0还是全1
int bitmap_byte_count (int bit_count); //将bit转换位byte,向上取整

int bitmap_get_bit (bitmap_t * bitmap, int index);//位图中某一个位的状态值
void bitmap_set_bit (bitmap_t * bitmap, int index, int count, int bit); //对连续count个内存页进行设置
int bitmap_is_set (bitmap_t * bitmap, int index); //判断某一位是否置0或者置1了
int bitmap_alloc_nbits (bitmap_t * bitmap, int bit, int count);//进程想要多少个页,bit表是想要1还是想要0和init_bit功能类似

#endif // BITMAP_H
//D:\code\x86\code\start\start\source\kernel\tools\bitmap.c
#include "tools/bitmap.h"
#include "tools/klib.h"

/**
 * @brief 获取所需要的字节数量
 */
int bitmap_byte_count (int bit_count) {
    return (bit_count + 8 - 1) / 8;         // 向上取整,前面算task sleep时间也用到了这个取整方法
}

/**
 * @brief 位图初始化
 */
void bitmap_init (bitmap_t * bitmap, uint8_t * bits, int count, int init_bit) {
    bitmap->bit_count = count;//位图需要多少位
    bitmap->bits = bits; //字节数组

    int bytes = bitmap_byte_count(bitmap->bit_count); //位图需要多少byte
    kernel_memset(bitmap->bits, init_bit ? 0xFF: 0, bytes); //利用uint8数组起始地址,给数组赋值,内存赋值函数是按字节为单位
}

/**
 * @brief 连续设置N个位
 */
void bitmap_set_bit (bitmap_t * bitmap, int index, int count, int bit) {
    for (int i = 0; (i < count) && (index < bitmap->bit_count); i++, index++) {
        // 可以考虑进行一定程序的优化!!
        if (bit) {
            bitmap->bits[index / 8] |= 1 << (index % 8);
        } else {
            bitmap->bits[index / 8] &= ~(1 << (index % 8));
        }
    }
} 

/**
 * @brief 获取指定位的状态
 */
int bitmap_get_bit (bitmap_t * bitmap, int index) {
    //return bitmap->bits[index / 8] & (1 << (index % 8));
    // 2023-3-9 这里应该返回0或者1
    return (bitmap->bits[index / 8] & (1 << (index % 8))) ? 1 : 0;
}

/**
 * @brief 检查指定位是否置1
 */
int bitmap_is_set (bitmap_t * bitmap, int index) {
    return bitmap_get_bit(bitmap, index) ? 1 : 0;
}

/**
 * @brief 连续分配若干指定比特位,返回起始索引
 */
int bitmap_alloc_nbits (bitmap_t * bitmap, int bit, int count) {
    int search_idx = 0;
    int ok_idx = -1;

    while (search_idx < bitmap->bit_count) {
        // 定位到第一个相同的索引处
        if (bitmap_get_bit(bitmap, search_idx) != bit) {
            // 不同,继续寻找起始的bit
            search_idx++;
            continue;
        }

        // 记录起始索引
        ok_idx = search_idx;

        // 继续计算下一部分
        int i;
        for (i = 1; (i < count) && (search_idx < bitmap->bit_count); i++) {
            if (bitmap_get_bit(bitmap, search_idx++) != bit) {
                // 不足count个,退出,重新进行最外层的比较
                ok_idx = -1;
                break;
            }
        }

        // 找到,设置各位,然后退出
        if (i >= count) {
            bitmap_set_bit(bitmap, ok_idx, count, ~bit); //将这些位设置为1,表示自己占用了这些空间
            return ok_idx;
        }
    }

    return -1;
}

利用位视图分配内存

需要一个结构体来囊括

//D:\code\x86\code\start\start\source\kernel\include\core\memory.h
#ifndef MEMORY_H
#define MEMORY_H

#include "tools/bitmap.h"
#include "comm/boot_info.h"
#include "ipc/mutex.h"

/**
 * @brief 地址分配结构
 */
typedef struct _addr_alloc_t { //专门涌来内存的分配与释放
    mutex_t mutex;              // 内存分配的互斥信号量
    bitmap_t bitmap;            // 辅助分配用的位图

    uint32_t page_size;         // 页(块)大小
    uint32_t start;             // 内存起始地址
    uint32_t size;              // 地址大小
}addr_alloc_t;

void memory_init (boot_info_t * boot_info); //初始化需要知道整个内存的分配信息,之前章节传出来的

#endif // MEMORY_H
//D:\code\x86\code\start\start\source\kernel\core\memory.c
/**
 * 内存管理
 *
 * 作者:李述铜
 * 联系邮箱: 527676163@qq.com
 */
#include "tools/klib.h"
#include "tools/log.h"
#include "core/memory.h"

/**
 * @brief 初始化地址分配结构
 * 以下不检查start和size的页边界,由上层调用者检查
 */
static void addr_alloc_init (addr_alloc_t * alloc, uint8_t * bits, uint32_t start, uint32_t size, uint32_t page_size) {
    mutex_init(&alloc->mutex);
    alloc->start = start;
    alloc->size = size; //KB一共大小
    alloc->page_size = page_size; //每一页大小
    bitmap_init(&alloc->bitmap, bits, alloc->size / page_size, 0);
}

/**
 * @brief 分配多页内存
 */
static uint32_t addr_alloc_page (addr_alloc_t * alloc, int page_count) {
    uint32_t addr = 0;

    mutex_lock(&alloc->mutex);

    int page_index = bitmap_alloc_nbits(&alloc->bitmap, 0, page_count); //连续分配page_count个页
    if (page_index >= 0) {
        addr = alloc->start + page_index * alloc->page_size;//这是分配出来内存的起始地址
    }

    mutex_unlock(&alloc->mutex);
    return addr;
}

/**
 * @brief 释放多页内存
 */
static void addr_free_page (addr_alloc_t * alloc, uint32_t addr, int page_count) {
    mutex_lock(&alloc->mutex);

    uint32_t pg_idx = (addr - alloc->start) / alloc->page_size;
    bitmap_set_bit(&alloc->bitmap, pg_idx, page_count, 0);

    mutex_unlock(&alloc->mutex);
}

/**
 * @brief 初始化内存管理系统
 * 该函数的主要任务:
 * 1、初始化物理内存分配器:将所有物理内存管理起来. 在1MB内存中分配物理位图
 * 2、重新创建内核页表:原loader中创建的页表已经不再合适
 */
void memory_init (boot_info_t * boot_info) {
    addr_alloc_t addr_alloc; //创建一个内存分配器
    uint8_t bits[8]; //位图

    addr_alloc_init(&addr_alloc, bits, 0x1000, 64*4096, 4096); //从4KB位置开始.页大小为4KB,分配256KB的内存大小
    
    for (int i = 0; i < 32; i++) {
        uint32_t addr = addr_alloc_page(&addr_alloc, 2);
        log_printf("alloc addr: 0x%x", addr);
    } //一共分配64页

    uint32_t addr = 0;
    for (int i = 0; i < 32; i++) {
        addr_free_page(&addr_alloc, addr, 2);
        addr += 8192;
    }
}

测试

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值