0x08_自制操作系统My-OS实现内存管理
内存管理就是内存管理,我不会像书一样解释。我直接教你怎么实现
还是把class05改class06或者复制一份
内存管理第一件事情就是要划出一篇区域,规定这个地方是内存区域
double *ptd = (double * ) memman_alloc (memman,30 * sizeof(double));和直接double ptd[30]有什么不同
double *ptd = (double * ) memman_alloc (memman,30 * sizeof(double));
是使用内存管理函数memman_alloc
分配了30个double
类型数据的连续内存块,并将该内存块的起始地址赋值给指针变量ptd
,即ptd
指向了这段连续的内存空间。这种方式分配的内存空间是在程序运行时动态分配的,因此可以灵活控制内存使用,但需要手动管理内存的分配和释放。
double ptd[30]
是在栈上直接分配了一个长度为30的double
数组,编译器会在编译时就为该数组分配内存空间,因此在程序运行时可以直接使用,不需要手动管理内存的分配和释放。这种方式分配的内存空间是静态分配的,因此在编译时需要确定数组长度,不能动态调整内存使用。
我们造的是操作系统,你开应用程序的时候是动态给他内存,关闭程序的时候是动态释放内存,内存管理是必要的。
head.h
int load_cr0(void); void store_cr0(int cr0);
放这里
//memory.c #define MEMMAN_ADDR 0x003c0000 #define EFLAGS_AC_BIT 0x00040000 #define CR0_CACHE_DISABLE 0x60000000 #define MEMMAN_FREES 4090 /* 大约是32KB*/ struct FREEINFO { /* 可用信息 */ unsigned int addr, size; }; struct MEMMAN { /* 内存管理 */ int frees, maxfrees, lostsize, losts; struct FREEINFO free[MEMMAN_FREES]; }; void memman_init(struct MEMMAN *man); unsigned int memman_total(struct MEMMAN *man); unsigned int memtest(unsigned int start, unsigned int end); int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); void memory(); unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size);
这个也加到head.h,这是memory.c的头文件
naskfun.asm
; naskfunc ; TAB=4 [FORMAT "WCOFF"] ; 制作目标文件的模式 [INSTRSET "i486p"] ; 使用到486为止的指令 [BITS 32] ; 3制作32位模式用的机器语言 [FILE "naskfunc.asm"] ; 文件名 GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt GLOBAL _io_load_eflags,_io_store_eflags,_asm_inthandler21 GLOBAL _load_gdtr, _load_idtr,_load_cr0,_store_cr0 GLOBAL _memtest_sub EXTERN _inthandler21 [SECTION .text] _io_hlt: ; void io_hlt(void); HLT RET _io_cli: ; void io_cli(void); CLI RET _io_sti: ; void io_sti(void); STI RET _io_get8: ; int io_get8(int port); MOV EDX,[ESP+4] ; port MOV EAX,0 IN AL,DX RET _io_set8: ; void io_set8(int port, int data); MOV EDX,[ESP+4] ; port MOV AL,[ESP+8] ; data OUT DX,AL RET _io_stihlt: ; void io_stihlt(void); STI HLT RET _write_mem8: ; void write_mem8(int addr, int data); MOV ECX,[ESP+4] ; taking content of add MOV AL,[ESP+8] ; taking content of data MOV [ECX],AL ; *ecx=al RET _io_load_eflags: ; int io_load_eflags(void); PUSHFD ; PUSH EFLAGS POP EAX RET _io_store_eflags: ; void io_store_eflags(int eflags); MOV EAX,[ESP+4] PUSH EAX POPFD ; POP EFLAGS RET _load_gdtr: ; void load_gdtr(int limit, int addr); MOV AX,[ESP+4] ; limit MOV [ESP+6],AX LGDT [ESP+6] RET _load_idtr: ; void load_idtr(int limit, int addr); MOV AX,[ESP+4] ; limit MOV [ESP+6],AX LIDT [ESP+6] RET _asm_inthandler21: PUSH ES PUSH DS PUSHAD MOV EAX,ESP PUSH EAX MOV AX,SS MOV DS,AX MOV ES,AX CALL _inthandler21 POP EAX POPAD POP DS POP ES IRETD _memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) PUSH EDI ; (由于还要使用EBX, ESI, EDI) PUSH ESI PUSH EBX MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; MOV EAX,[ESP+12+4] ; i = start; mts_loop: MOV EBX,EAX ADD EBX,0xffc ; p = i + 0xffc; MOV EDX,[EBX] ; old = *p; MOV [EBX],ESI ; *p = pat0; XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; CMP EDI,[EBX] ; if (*p != pat1) goto fin; JNE mts_fin XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; CMP ESI,[EBX] ; if (*p != pat0) goto fin; JNE mts_fin MOV [EBX],EDX ; *p = old; ADD EAX,0x1000 ; i += 0x1000; CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; JBE mts_loop POP EBX POP ESI POP EDI RET mts_fin: MOV [EBX],EDX ; *p = old; POP EBX POP ESI POP EDI RET _load_cr0: ; int load_cr0(void); MOV EAX,CR0 RET _store_cr0: ; void store_cr0(int cr0); MOV EAX,[ESP+4] MOV CR0,EAX RET
加粗的都是新增的
创建新文件memory.c
#include "include/head.h" #include <stdio.h> unsigned int memtest(unsigned int start, unsigned int end) { char flg486 = 0; unsigned int eflg, cr0, i; /* 确认CPU是386还是486以上的 */ eflg = io_load_eflags(); eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ io_store_eflags(eflg); eflg = io_load_eflags(); if ((eflg & EFLAGS_AC_BIT) != 0) { /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ flg486 = 1; } eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ io_store_eflags(eflg); if (flg486 != 0) { cr0 = load_cr0(); cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ store_cr0(cr0); } i = memtest_sub(start, end); if (flg486 != 0) { cr0 = load_cr0(); cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ store_cr0(cr0); } return i; } void memman_init(struct MEMMAN *man) { man->frees = 0; /* 可用信息数目 */ man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ man->lostsize = 0; /* 释放失败的内存的大小总和 */ man->losts = 0; /* 释放失败次数 */ return; } unsigned int memman_total(struct MEMMAN *man) /* 报告空余内存大小的合计 */ { unsigned int i, t = 0; for (i = 0; i < man->frees; i++) { t += man->free[i].size; } return t; } unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) /* 分配 */ { unsigned int i, a; for (i = 0; i < man->frees; i++) { if (man->free[i].size >= size) { /* 找到了足够大的内存 */ a = man->free[i].addr; man->free[i].addr += size; man->free[i].size -= size; if (man->free[i].size == 0) { /* 如果free[i]变成了0,就减掉一条可用信息 */ man->frees--; for (; i < man->frees; i++) { man->free[i] = man->free[i + 1]; /* 代入结构体 */ } } return a; } } return 0; /* 没有可用空间 */ } int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) /* 释放 */ { int i, j; /* 为便于归纳内存,将free[]按照addr的顺序排列 */ /* 所以,先决定应该放在哪里 */ for (i = 0; i < man->frees; i++) { if (man->free[i].addr > addr) { break; } } /* free[i - 1].addr < addr < free[i].addr */ if (i > 0) { /* 前面有可用内存 */ if (man->free[i - 1].addr + man->free[i - 1].size == addr) { /* 可以与前面的可用内存归纳到一起 */ man->free[i - 1].size += size; if (i < man->frees) { /* 后面也有 */ if (addr + size == man->free[i].addr) { /* 也可以与后面的可用内存归纳到一起 */ man->free[i - 1].size += man->free[i].size; /* man->free[i]删除 */ /* free[i]变成0后归纳到前面去 */ man->frees--; for (; i < man->frees; i++) { man->free[i] = man->free[i + 1]; /* 结构体赋值 */ } } } return 0; /* 成功完成 */ } } /* 不能与前面的可用空间归纳到一起 */ if (i < man->frees) { /* 后面还有 */ if (addr + size == man->free[i].addr) { /* 可以与后面的内容归纳到一起 */ man->free[i].addr = addr; man->free[i].size += size; return 0; /* 成功完成 */ } } /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ if (man->frees < MEMMAN_FREES) { /* free[i]之后的,向后移动,腾出一点可用空间 */ for (j = man->frees; j > i; j--) { man->free[j] = man->free[j - 1]; } man->frees++; if (man->maxfrees < man->frees) { man->maxfrees = man->frees; /* 更新最大值 */ } man->free[i].addr = addr; man->free[i].size = size; return 0; /* 成功完成 */ } /* 不能往后移动 */ man->losts++; man->lostsize += size; return -1; /* 失败 */ } unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) { unsigned int a; size = (size + 0xfff) & 0xfffff000; a = memman_alloc(man, size); return a; } int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) { int i; size = (size + 0xfff) & 0xfffff000; i = memman_free(man, addr, size); return i; } void memory(){ char s[30]; struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; unsigned int memtotal; struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; memtotal = memtest(0x00400000, 0xbfffffff); memman_init(memman); memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ memman_free(memman, 0x00400000, memtotal - 0x00400000); // double * ptd; // ptd = (double * ) memman_alloc (memman,30 * sizeof(double)); char q[2048]; sprintf(s, "memory %dKB free : %dKB", memtotal / (1024), memman_total(memman) / (1024)); putfonts8_asc(binfo->vram, binfo->scrnx, 0, binfo->scrny-16,2, s); }
在Main里面调用memory方法
最后在makefile里面加上obj
运行:
cd class05 ..\z_tools\make.exe run
我换了底色,这样显得更加成熟
自制操作系统合集
原文地址:https://www.cnblogs.com/Frank-dev-blog/category/2249116.html
项目github地址rick521/My-OS (github.com)给我点颗star