1 /**
2  * @file mm-stat.c
3  * @author longjin(longjin@RinGoTek.cn)
4  * @brief 查询内存信息
5  * @version 0.1
6  * @date 2022-08-06
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 
12 #include "mm.h"
13 #include "slab.h"
14 #include <common/errno.h>
15 #include <process/ptrace.h>
16 
17 extern const struct slab kmalloc_cache_group[16];
18 
19 static int __empty_2m_pages(int zone);
20 static int __count_in_using_2m_pages(int zone);
21 static uint64_t __count_kmalloc_free();
22 static uint64_t __count_kmalloc_using();
23 static uint64_t __count_kmalloc_total();
24 uint64_t sys_mm_stat(struct pt_regs *regs);
25 
26 /**
27  * @brief 获取指定zone中的空闲2M页的数量
28  *
29  * @param zone 内存zone号
30  * @return int 空闲2M页数量
31  */
__count_empty_2m_pages(int zone)32 static int __count_empty_2m_pages(int zone)
33 {
34     int zone_start = 0, zone_end = 0;
35 
36     uint64_t attr = 0;
37     switch (zone)
38     {
39     case ZONE_DMA:
40         // DMA区域
41         zone_start = 0;
42         zone_end = ZONE_DMA_INDEX;
43         attr |= PAGE_PGT_MAPPED;
44         break;
45     case ZONE_NORMAL:
46         zone_start = ZONE_DMA_INDEX;
47         zone_end = ZONE_NORMAL_INDEX;
48         attr |= PAGE_PGT_MAPPED;
49         break;
50     case ZONE_UNMAPPED_IN_PGT:
51         zone_start = ZONE_NORMAL_INDEX;
52         zone_end = ZONE_UNMAPPED_INDEX;
53         attr = 0;
54         break;
55     default:
56         kerror("In __count_empty_2m_pages: param: zone invalid.");
57         // 返回错误码
58         return -EINVAL;
59         break;
60     }
61 
62     uint64_t result = 0;
63     for (int i = zone_start; i <= zone_end; ++i)
64     {
65         result += (memory_management_struct.zones_struct + i)->count_pages_free;
66     }
67     return result;
68 }
69 
70 /**
71  * @brief 获取指定zone中的正在使用的2M页的数量
72  *
73  * @param zone 内存zone号
74  * @return int 空闲2M页数量
75  */
__count_in_using_2m_pages(int zone)76 static int __count_in_using_2m_pages(int zone)
77 {
78     int zone_start = 0, zone_end = 0;
79 
80     uint64_t attr = 0;
81     switch (zone)
82     {
83     case ZONE_DMA:
84         // DMA区域
85         zone_start = 0;
86         zone_end = ZONE_DMA_INDEX;
87         attr |= PAGE_PGT_MAPPED;
88         break;
89     case ZONE_NORMAL:
90         zone_start = ZONE_DMA_INDEX;
91         zone_end = ZONE_NORMAL_INDEX;
92         attr |= PAGE_PGT_MAPPED;
93         break;
94     case ZONE_UNMAPPED_IN_PGT:
95         zone_start = ZONE_NORMAL_INDEX;
96         zone_end = ZONE_UNMAPPED_INDEX;
97         attr = 0;
98         break;
99     default:
100         kerror("In __count_in_using_2m_pages: param: zone invalid.");
101         // 返回错误码
102         return -EINVAL;
103         break;
104     }
105 
106     uint64_t result = 0;
107     for (int i = zone_start; i <= zone_end; ++i)
108     {
109         result += (memory_management_struct.zones_struct + i)->count_pages_using;
110     }
111     return result;
112 }
113 
114 /**
115  * @brief 计算kmalloc缓冲区中的空闲内存
116  *
117  * @return uint64_t 空闲内存(字节)
118  */
__count_kmalloc_free()119 static uint64_t __count_kmalloc_free()
120 {
121     uint64_t result = 0;
122     for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
123     {
124         result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_free;
125     }
126     return result;
127 }
128 
129 /**
130  * @brief 计算kmalloc缓冲区中已使用的内存
131  *
132  * @return uint64_t 已使用的内存(字节)
133  */
__count_kmalloc_using()134 static uint64_t __count_kmalloc_using()
135 {
136     uint64_t result = 0;
137     for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
138     {
139         result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_using;
140     }
141     return result;
142 }
143 
144 /**
145  * @brief 计算kmalloc缓冲区中总共占用的内存
146  *
147  * @return uint64_t 缓冲区占用的内存(字节)
148  */
__count_kmalloc_total()149 static uint64_t __count_kmalloc_total()
150 {
151     uint64_t result = 0;
152     for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
153     {
154         result += kmalloc_cache_group[i].size * (kmalloc_cache_group[i].count_total_free + kmalloc_cache_group[i].count_total_using);
155     }
156     return result;
157 }
158 
159 /**
160  * @brief 获取系统当前的内存信息(未上锁,不一定精准)
161  *
162  * @return struct mm_stat_t 内存信息结构体
163  */
mm_stat()164 struct mm_stat_t mm_stat()
165 {
166     struct mm_stat_t tmp = {0};
167     // 统计物理页的信息
168     tmp.used = __count_in_using_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
169     tmp.free = __count_empty_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
170     tmp.total = tmp.used + tmp.free;
171     tmp.shared = 0;
172     // 统计kmalloc slab中的信息
173     tmp.cache_free = __count_kmalloc_free();
174     tmp.cache_used = __count_kmalloc_using();
175     tmp.available = tmp.free + tmp.cache_free;
176     return tmp;
177 }
178 
179 /**
180  * @brief 获取内存信息的系统调用
181  *
182  * @param r8 返回的内存信息结构体的地址
183  * @return uint64_t
184  */
sys_mstat(struct pt_regs * regs)185 uint64_t sys_mstat(struct pt_regs *regs)
186 {
187     if (regs->r8 == NULL)
188         return -EINVAL;
189     struct mm_stat_t stat = mm_stat();
190     if (regs->cs == (USER_CS | 0x3))
191         copy_to_user((void *)regs->r8, &stat, sizeof(struct mm_stat_t));
192     else
193         memcpy((void *)regs->r8, &stat, sizeof(struct mm_stat_t));
194     return 0;
195 }