diff --git a/kernel/mm/Makefile b/kernel/mm/Makefile index d604d817..fbe16790 100644 --- a/kernel/mm/Makefile +++ b/kernel/mm/Makefile @@ -2,7 +2,7 @@ CFLAGS += -I . -all:mm.o slab.o +all:mm.o slab.o mm-stat.o mm.o: mm.c gcc $(CFLAGS) -c mm.c -o mm.o @@ -10,3 +10,5 @@ mm.o: mm.c slab.o: slab.c gcc $(CFLAGS) -c slab.c -o slab.o +mm-stat.o: mm-stat.c + gcc $(CFLAGS) -c mm-stat.c -o mm-stat.o diff --git a/kernel/mm/mm-stat.c b/kernel/mm/mm-stat.c new file mode 100644 index 00000000..976984a5 --- /dev/null +++ b/kernel/mm/mm-stat.c @@ -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 +#include + +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; +} \ No newline at end of file diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index 7e1b5cd4..38614630 100644 --- a/kernel/mm/mm.h +++ b/kernel/mm/mm.h @@ -145,7 +145,7 @@ do \ { \ ul tmp; \ - io_mfence();\ + io_mfence(); \ __asm__ __volatile__( \ "movq %%cr3, %0\n\t" \ "movq %0, %%cr3\n\t" \ @@ -227,6 +227,21 @@ struct Page ul age; }; +/** + * @brief 系统内存信息结构体(单位:字节) + * + */ +struct mm_stat_t +{ + uint64_t total; // 计算机的总内存数量大小 + uint64_t used; // 已使用的内存大小 + uint64_t free; // 空闲物理页所占的内存大小 + uint64_t shared; // 共享的内存大小 + uint64_t cache_used; // 位于slab缓冲区中的已使用的内存大小 + uint64_t cache_free; // 位于slab缓冲区中的空闲的内存大小 + uint64_t available; // 系统总空闲内存大小(包括kmalloc缓冲区) +}; + extern struct memory_desc memory_management_struct; // 导出内核程序的几个段的起止地址 @@ -443,4 +458,11 @@ int8_t mm_check_page_table(uint64_t *ptr); * @param offset 新的地址相对于原地址的偏移量 * @return uint64_t */ -uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset); \ No newline at end of file +uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset); + +/** + * @brief 获取系统当前的内存信息(未上锁,不一定精准) + * + * @return struct mm_stat_t 内存信息结构体 + */ +struct mm_stat_t mm_stat(); \ No newline at end of file diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 5a18ec1b..2b3fb44d 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -18,6 +18,7 @@ extern void system_call(void); extern void syscall_int(void); extern uint64_t sys_clock(struct pt_regs *regs); +extern uint64_t sys_mstat(struct pt_regs *regs); /** * @brief 导出系统调用处理函数的符号 @@ -778,5 +779,7 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = [17] = sys_mkdir, [18] = sys_nanosleep, [19] = sys_clock, - [20 ... 254] = system_call_not_exists, + [20] = system_call_not_exists, + [21] = sys_mstat, + [22 ... 254] = system_call_not_exists, [255] = sys_ahci_end_req}; diff --git a/kernel/syscall/syscall_num.h b/kernel/syscall/syscall_num.h index 633ef8ba..661132f6 100644 --- a/kernel/syscall/syscall_num.h +++ b/kernel/syscall/syscall_num.h @@ -30,5 +30,9 @@ #define SYS_MKDIR 17 // 创建文件夹 #define SYS_NANOSLEEP 18 // 纳秒级休眠 #define SYS_CLOCK 19 // 获取当前cpu时间 +#define SYS_PIPE 20 + +#define SYS_MSTAT 21 // 获取系统的内存状态信息 + #define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用 \ No newline at end of file diff --git a/user/libs/libc/sys/stat.c b/user/libs/libc/sys/stat.c index 397014c2..6918beb4 100644 --- a/user/libs/libc/sys/stat.c +++ b/user/libs/libc/sys/stat.c @@ -1,7 +1,18 @@ #include "stat.h" -#include +#include int mkdir(const char *path, mode_t mode) { - return syscall_invoke(SYS_MKDIR, (uint64_t)path, (uint64_t)mode, 0,0,0,0,0,0); + return syscall_invoke(SYS_MKDIR, (uint64_t)path, (uint64_t)mode, 0, 0, 0, 0, 0, 0); +} + +/** + * @brief 获取系统的内存信息 + * + * @param stat 传入的内存信息结构体 + * @return int 错误码 + */ +int mstat(struct mstat_t *stat) +{ + return syscall_invoke(SYS_MSTAT, (uint64_t)stat, 0, 0, 0, 0, 0, 0, 0); } \ No newline at end of file diff --git a/user/libs/libc/sys/stat.h b/user/libs/libc/sys/stat.h index 794dece7..2e72c8d4 100644 --- a/user/libs/libc/sys/stat.h +++ b/user/libs/libc/sys/stat.h @@ -1,4 +1,27 @@ #pragma once #include -int mkdir(const char *path, mode_t mode); \ No newline at end of file +/** + * @brief 系统内存信息结构体(单位:字节) + * + */ +struct mstat_t +{ + uint64_t total; // 计算机的总内存数量大小 + uint64_t used; // 已使用的内存大小 + uint64_t free; // 空闲物理页所占的内存大小 + uint64_t shared; // 共享的内存大小 + uint64_t cache_used; // 位于slab缓冲区中的已使用的内存大小 + uint64_t cache_free; // 位于slab缓冲区中的空闲的内存大小 + uint64_t available; // 系统总空闲内存大小(包括kmalloc缓冲区) +}; + +int mkdir(const char *path, mode_t mode); + +/** + * @brief 获取系统的内存信息 + * + * @param stat 传入的内存信息结构体 + * @return int 错误码 + */ +int mstat(struct mstat_t* stat); \ No newline at end of file diff --git a/user/libs/libsystem/syscall.h b/user/libs/libsystem/syscall.h index 942f8750..1b379fff 100644 --- a/user/libs/libsystem/syscall.h +++ b/user/libs/libsystem/syscall.h @@ -24,6 +24,9 @@ #define SYS_MKDIR 17 // 创建文件夹 #define SYS_NANOSLEEP 18 // 纳秒级休眠 #define SYS_CLOCK 19 // 获取当前cpu时间 +#define SYS_PIPE 20 + +#define SYS_MSTAT 21 // 获取系统的内存状态信息 /** * @brief 用户态系统调用函数