|  | @@ -0,0 +1,195 @@
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @file mm-stat.c
 | 
	
		
			
				|  |  | + * @author longjin(longjin@RinGoTek.cn)
 | 
	
		
			
				|  |  | + * @brief 查询内存信息
 | 
	
		
			
				|  |  | + * @version 0.1
 | 
	
		
			
				|  |  | + * @date 2022-08-06
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @copyright Copyright (c) 2022
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include "mm.h"
 | 
	
		
			
				|  |  | +#include "slab.h"
 | 
	
		
			
				|  |  | +#include <common/errno.h>
 | 
	
		
			
				|  |  | +#include <process/ptrace.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +extern const struct slab kmalloc_cache_group[16];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int __empty_2m_pages(int zone);
 | 
	
		
			
				|  |  | +static int __count_in_using_2m_pages(int zone);
 | 
	
		
			
				|  |  | +static uint64_t __count_kmalloc_free();
 | 
	
		
			
				|  |  | +static uint64_t __count_kmalloc_using();
 | 
	
		
			
				|  |  | +static uint64_t __count_kmalloc_total();
 | 
	
		
			
				|  |  | +uint64_t sys_mm_stat(struct pt_regs *regs);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 获取指定zone中的空闲2M页的数量
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param zone 内存zone号
 | 
	
		
			
				|  |  | + * @return int 空闲2M页数量
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int __count_empty_2m_pages(int zone)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int zone_start = 0, zone_end = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    uint64_t attr = 0;
 | 
	
		
			
				|  |  | +    switch (zone)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +    case ZONE_DMA:
 | 
	
		
			
				|  |  | +        // DMA区域
 | 
	
		
			
				|  |  | +        zone_start = 0;
 | 
	
		
			
				|  |  | +        zone_end = ZONE_DMA_INDEX;
 | 
	
		
			
				|  |  | +        attr |= PAGE_PGT_MAPPED;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case ZONE_NORMAL:
 | 
	
		
			
				|  |  | +        zone_start = ZONE_DMA_INDEX;
 | 
	
		
			
				|  |  | +        zone_end = ZONE_NORMAL_INDEX;
 | 
	
		
			
				|  |  | +        attr |= PAGE_PGT_MAPPED;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case ZONE_UNMAPPED_IN_PGT:
 | 
	
		
			
				|  |  | +        zone_start = ZONE_NORMAL_INDEX;
 | 
	
		
			
				|  |  | +        zone_end = ZONE_UNMAPPED_INDEX;
 | 
	
		
			
				|  |  | +        attr = 0;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    default:
 | 
	
		
			
				|  |  | +        kerror("In __count_empty_2m_pages: param: zone invalid.");
 | 
	
		
			
				|  |  | +        // 返回错误码
 | 
	
		
			
				|  |  | +        return -EINVAL;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    uint64_t result = 0;
 | 
	
		
			
				|  |  | +    for (int i = zone_start; i <= zone_end; ++i)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        result += (memory_management_struct.zones_struct + i)->count_pages_free;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return result;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 获取指定zone中的正在使用的2M页的数量
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param zone 内存zone号
 | 
	
		
			
				|  |  | + * @return int 空闲2M页数量
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int __count_in_using_2m_pages(int zone)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int zone_start = 0, zone_end = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    uint64_t attr = 0;
 | 
	
		
			
				|  |  | +    switch (zone)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +    case ZONE_DMA:
 | 
	
		
			
				|  |  | +        // DMA区域
 | 
	
		
			
				|  |  | +        zone_start = 0;
 | 
	
		
			
				|  |  | +        zone_end = ZONE_DMA_INDEX;
 | 
	
		
			
				|  |  | +        attr |= PAGE_PGT_MAPPED;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case ZONE_NORMAL:
 | 
	
		
			
				|  |  | +        zone_start = ZONE_DMA_INDEX;
 | 
	
		
			
				|  |  | +        zone_end = ZONE_NORMAL_INDEX;
 | 
	
		
			
				|  |  | +        attr |= PAGE_PGT_MAPPED;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case ZONE_UNMAPPED_IN_PGT:
 | 
	
		
			
				|  |  | +        zone_start = ZONE_NORMAL_INDEX;
 | 
	
		
			
				|  |  | +        zone_end = ZONE_UNMAPPED_INDEX;
 | 
	
		
			
				|  |  | +        attr = 0;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    default:
 | 
	
		
			
				|  |  | +        kerror("In __count_in_using_2m_pages: param: zone invalid.");
 | 
	
		
			
				|  |  | +        // 返回错误码
 | 
	
		
			
				|  |  | +        return -EINVAL;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    uint64_t result = 0;
 | 
	
		
			
				|  |  | +    for (int i = zone_start; i <= zone_end; ++i)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        result += (memory_management_struct.zones_struct + i)->count_pages_using;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return result;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 计算kmalloc缓冲区中的空闲内存
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @return uint64_t 空闲内存(字节)
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static uint64_t __count_kmalloc_free()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    uint64_t result = 0;
 | 
	
		
			
				|  |  | +    for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_free;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return result;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 计算kmalloc缓冲区中已使用的内存
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @return uint64_t 已使用的内存(字节)
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static uint64_t __count_kmalloc_using()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    uint64_t result = 0;
 | 
	
		
			
				|  |  | +    for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_using;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return result;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 计算kmalloc缓冲区中总共占用的内存
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @return uint64_t 缓冲区占用的内存(字节)
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static uint64_t __count_kmalloc_total()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    uint64_t result = 0;
 | 
	
		
			
				|  |  | +    for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        result += kmalloc_cache_group[i].size * (kmalloc_cache_group[i].count_total_free + kmalloc_cache_group[i].count_total_using);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return result;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 获取系统当前的内存信息(未上锁,不一定精准)
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * @return struct mm_stat_t 内存信息结构体
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +struct mm_stat_t mm_stat()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    struct mm_stat_t tmp = {0};
 | 
	
		
			
				|  |  | +    // 统计物理页的信息
 | 
	
		
			
				|  |  | +    tmp.used = __count_in_using_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
 | 
	
		
			
				|  |  | +    tmp.free = __count_empty_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
 | 
	
		
			
				|  |  | +    tmp.total = tmp.used + tmp.free;
 | 
	
		
			
				|  |  | +    tmp.shared = 0;
 | 
	
		
			
				|  |  | +    // 统计kmalloc slab中的信息
 | 
	
		
			
				|  |  | +    tmp.cache_free = __count_kmalloc_free();
 | 
	
		
			
				|  |  | +    tmp.cache_used = __count_kmalloc_using();
 | 
	
		
			
				|  |  | +    tmp.available = tmp.free + tmp.cache_free;
 | 
	
		
			
				|  |  | +    return tmp;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @brief 获取内存信息的系统调用
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param r8 返回的内存信息结构体的地址
 | 
	
		
			
				|  |  | + * @return uint64_t
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +uint64_t sys_mstat(struct pt_regs *regs)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (regs->r8 == NULL)
 | 
	
		
			
				|  |  | +        return -EINVAL;
 | 
	
		
			
				|  |  | +    struct mm_stat_t stat = mm_stat();
 | 
	
		
			
				|  |  | +    if (regs->cs == (USER_CS | 0x3))
 | 
	
		
			
				|  |  | +        copy_to_user((void *)regs->r8, &stat, sizeof(struct mm_stat_t));
 | 
	
		
			
				|  |  | +    else
 | 
	
		
			
				|  |  | +        memcpy((void *)regs->r8, &stat, sizeof(struct mm_stat_t));
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +}
 |