This commit is contained in:
2021-09-14 18:35:13 +03:00
parent 4e5c38d0ff
commit f052f2294e
32 changed files with 525 additions and 522 deletions

View File

@ -16,13 +16,20 @@ goto build
:build
@echo Building Memory Manager...
del %objpath%\mmngr_cr.o
del %objpath%\mmngr.o
del %objpath%\mmngr_ph.o
@echo * Compiling Physical Memory Manager...
%nasm_path%\nasm.exe -f aout -o %objpath%/mmngr_cr.o mmngr_cr.asm
%nasm_path%\nasm.exe -f aout -o %objpath%/mmngr.o mmngr.asm
%djgpp_path%\gcc.exe -Wall -O -fstrength-reduce -fomit-frame-pointer -nostdinc -fno-builtin -I%incpath% -c -o %objpath%/mmngr_ph.o mmngr_ph.c
@echo * Compiling Virtual Memory Manager...
%djgpp_path%\gcc.exe -Wall -O -fstrength-reduce -fomit-frame-pointer -nostdinc -fno-builtin -I%incpath% -c -o %objpath%/mmngr_vi.o mmngr_vi.c
%djgpp_path%\gcc.exe -Wall -O -fstrength-reduce -fomit-frame-pointer -nostdinc -fno-builtin -I%incpath% -c -o %objpath%/mmngr_de.o lib/pde.c
%djgpp_path%\gcc.exe -Wall -O -fstrength-reduce -fomit-frame-pointer -nostdinc -fno-builtin -I%incpath% -c -o %objpath%/mmngr_te.o lib/pte.c
:check
if not exist %objpath%\mmngr_cr.o goto error
if not exist %objpath%\mmngr_vi.o goto error
if not exist %objpath%\mmngr_de.o goto error
if not exist %objpath%\mmngr_te.o goto error
if not exist %objpath%\mmngr.o goto error
if not exist %objpath%\mmngr_ph.o goto error

36
SysCore/memory/lib/pde.c Normal file
View File

@ -0,0 +1,36 @@
#include "pde.h"
void pd_entry_add_attrib (pd_entry* entry, unsigned mask) {
*entry |= mask;
}
void pd_entry_del_attrib (pd_entry* entry, unsigned mask) {
*entry &= ~mask;
}
void pd_entry_set_frame (pd_entry* entry, unsigned address) {
*entry = (*entry & ~_I86_PDE_FRAME) | address;
}
unsigned pd_entry_get_frame (pd_entry entry) {
return entry&_I86_PDE_FRAME;
}
unsigned char pd_entry_is_present (pd_entry entry) {
return (entry & _I86_PDE_PRESENT);
}
unsigned char pd_entry_is_user (pd_entry entry) {
return (entry & _I86_PDE_USER);
}
unsigned char pd_entry_is_4mb (pd_entry entry) {
return (entry & _I86_PDE_4MB);
}
unsigned char pd_entry_is_writable (pd_entry entry) {
return (entry & _I86_PDE_WRITABLE);
}
void pd_entry_enable_global (pd_entry entry) {
}

30
SysCore/memory/lib/pde.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef __PAGE_DIRECTORY_ENTRY_
#define __PAGE_DIRECTORY_ENTRY_
enum __PAGE_PDE_FLAGS {
_I86_PDE_PRESENT = 1,
_I86_PDE_WRITABLE = 2,
_I86_PDE_USER = 4,
_I86_PDE_PWT = 8,
_I86_PDE_PCD = 0x10,
_I86_PDE_ACCESSED = 0x20,
_I86_PDE_DIRTY = 0x40,
_I86_PDE_4MB = 0x80,
_I86_PDE_CPU_GLOBAL = 0x100,
_I86_PDE_LV4_GLOBAL = 0x200,
_I86_PDE_FRAME = 0x7FFFF000
};
typedef unsigned pd_entry;
extern void pd_entry_add_attrib (pd_entry* entry, unsigned mask);
extern void pd_entry_del_attrib (pd_entry* entry, unsigned mask);
extern void pd_entry_set_frame (pd_entry* entry, unsigned address);
extern unsigned pd_entry_get_frame (pd_entry entry);
extern unsigned char pd_entry_is_present (pd_entry entry);
extern unsigned char pd_entry_is_user (pd_entry entry);
extern unsigned char pd_entry_is_4mb (pd_entry entry);
extern unsigned char pd_entry_is_writable (pd_entry entry);
extern void pd_entry_enable_global (pd_entry entry);
#endif

View File

@ -1,4 +1,4 @@
#include <pte.h>
#include "pte.h"
void pt_entry_add_attrib (pt_entry* entry, unsigned mask) {
*entry |= mask;
@ -9,18 +9,17 @@ void pt_entry_add_attrib (pt_entry* entry, unsigned mask) {
}
void pt_entry_set_frame (pt_entry* entry, unsigned address) {
*entry &= ~_I86_PTE_FRAME;
*entry |= address & _I86_PTE_FRAME;
*entry = (*entry & ~_I86_PTE_FRAME) | address;
}
unsigned pt_entry_get_frame (pt_entry entry) {
return entry&_I86_PTE_FRAME;
return (entry & _I86_PTE_FRAME);
}
unsigned char pt_entry_is_present (pt_entry entry) {
return ( (entry & _I86_PTE_PRESENT) > 0 );
return (entry & _I86_PTE_PRESENT);
}
unsigned char pt_entry_is_writable (pt_entry entry) {
return ( (entry & _I86_PTE_WRITABLE) > 0 );
return (entry & _I86_PTE_WRITABLE);
}

View File

@ -27,3 +27,11 @@ _write_cr3:
mov cr3, eax
pop ebp
retn
global _vmmngr_flush_tbl_entry
_vmmngr_flush_tbl_entry:
mov eax, [ebp+8]
cli
invlpg [eax]
sti
retn

View File

@ -1,26 +1,34 @@
/******************************************************
* Physical Memory Manager *
******************************************************/
#include <system.h>
#include <string.h>
// +==============================================+
// | HEADERS |
// +===================================== cta os =+
#include "mmngr_ph.h"
// +==============================================+
// | DEFINITIONS |
// +===================================== cta os =+
#define PMMNGR_BLOCK_SIZE 4096 // block size (4k)
#define PMMNGR_BLOCK_ALIGN PMMNGR_BLOCK_SIZE // block alignment
struct memory_stack_entry{
word low;
byte high;
} __attribute__ ((__packed__));
typedef struct memory_stack_entry mstack;
static uint32_t _mmngr_memory_size=0; // size of physical memory
static uint32_t _mmngr_used_blocks=0; // number of blocks currently in use
static uint32_t _mmngr_max_blocks=0; // maximum number of available memory blocks
static uint32_t _mmngr_index = 0;
// +==============================================+
// | DATA DECLARATIONS |
// +===================================== cta os =+
static unsigned _mmngr_memory_size=0; // size of physical memory
static unsigned _mmngr_used_blocks=0; // number of blocks currently in use
static unsigned _mmngr_max_blocks=0; // maximum number of available memory blocks
static unsigned _mmngr_index = 0;
static mstack* _mmngr_memory_stack= 0; // memory stack
// +==============================================+
// | LOCAL FUNCTIONS |
// +===================================== cta os =+
inline mstack mstack_pop ()
{
mstack temp;
@ -34,7 +42,6 @@ inline mstack mstack_pop ()
return temp;
}
inline void mstack_push (const mstack *block)
{
if (block->low == 0 && block-> high == 0) return;
@ -46,54 +53,90 @@ inline void mstack_push (const mstack *block)
_mmngr_used_blocks--;
}
inline byte mstack_test (const mstack *block)
inline int mstack_test (const mstack *block)
{
uint32_t i;
unsigned i;
for (i = 0; i < _mmngr_index; i++)
if (_mmngr_memory_stack[i].low == block->low && _mmngr_memory_stack[i].high == block->high) return 1;
if (_mmngr_memory_stack[i].low == block->low && _mmngr_memory_stack[i].high == block->high)
return (int) i;
return 0;
return -1;
}
byte pmmngr_test_block (uint32_t block)
inline int mstack_qsort_cmp (mstack a, mstack b)
{
mstack temp;
temp.low = block & 0xFFFF;
temp.high = (block>>16) & 0xFF;
return mstack_test(&temp);
return (a.high == b.high) ? (int)a.low - (int)b.low : (int)a.high - (int)b.high;
}
void pmmngr_free_block(void* address)
void mstack_qsort(int beg, int end)
{
// Calculate block
mstack block;
uint32_t temp = (uint32_t)address / PMMNGR_BLOCK_SIZE;
block.low = temp & 0xFFFF;
block.high = (temp>>16) & 0xFF;
// Push it
mstack_push (&block);
mstack piv; mstack tmp;
int l,r,p;
while (beg<end) // This while loop will avoid the second recursive call
{
l = beg; p = (beg+end)/2; r = end;
piv.low = _mmngr_memory_stack[p].low;
piv.high = _mmngr_memory_stack[p].high;
while (1)
{
while ((l<=r) && (mstack_qsort_cmp(_mmngr_memory_stack[l],piv) <= 0)) l++;
while ((l<=r) && (mstack_qsort_cmp(_mmngr_memory_stack[r],piv) > 0)) r--;
if (l>r) break;
tmp.low = _mmngr_memory_stack[l].low;
tmp.high = _mmngr_memory_stack[l].high;
_mmngr_memory_stack[l].low = _mmngr_memory_stack[r].low;
_mmngr_memory_stack[l].high = _mmngr_memory_stack[r].high;
_mmngr_memory_stack[r].low = tmp.low;
_mmngr_memory_stack[r].high = tmp.high;
if (p==r) p=l;
l++; r--;
}
_mmngr_memory_stack[p].low = _mmngr_memory_stack[r].low;
_mmngr_memory_stack[p].high = _mmngr_memory_stack[r].high;
_mmngr_memory_stack[r].low = piv.low;
_mmngr_memory_stack[r].high = piv.high;
r--;
// Recursion on the shorter side & loop (with new indexes) on the longer
if ((r-beg)<(end-l)) {
mstack_qsort(beg, r);
beg=l;
}
else {
mstack_qsort(l, end);
end=r;
}
}
}
void* pmmngr_alloc_block()
// +==============================================+
// | DEBUGGING FUNCTIONS |
// +===================================== cta os =+
/*void print_stack()
{
if (_mmngr_index == 0) return 0;// Out of memory
// pop a block
mstack block = mstack_pop();
// Calculate and return address;
void* address;
uint32_t temp = block.low | (block.high<<16);
address = (void *)(temp * PMMNGR_BLOCK_SIZE);
return address;
int i;
for (i = 0; i < _mmngr_index; i++) printf (" %u", _mmngr_memory_stack[i].low);
}
extern char getch();*/
void pmmngr_init (size_t memSize, uint32_t stack) {
// +==============================================+
// | INITIALISATION FUNCTIONS |
// +===================================== cta os =+
void pmmngr_init (unsigned memSize, unsigned stack) {
_mmngr_memory_size = memSize;
_mmngr_memory_stack = (mstack*) stack;
@ -104,7 +147,7 @@ void pmmngr_init (size_t memSize, uint32_t stack) {
// By default, all of memory is in use
}
void pmmngr_init_region (physical_addr base, size_t size) {
void pmmngr_init_region (unsigned base, unsigned size) {
mstack block;
@ -121,7 +164,7 @@ void pmmngr_init_region (physical_addr base, size_t size) {
}
void pmmngr_deinit_region (physical_addr base, size_t size) {
void pmmngr_deinit_region (unsigned base, unsigned size) {
unsigned int start = base / PMMNGR_BLOCK_SIZE;
unsigned int count = size / PMMNGR_BLOCK_SIZE;
int temp;
@ -161,28 +204,136 @@ void pmmngr_deinit_region (physical_addr base, size_t size) {
}
size_t pmmngr_get_memory_size () {
// +==============================================+
// | MEMORY MANAGING FUNCTIONS |
// +===================================== cta os =+
unsigned char pmmngr_test_block (unsigned block)
{
mstack temp;
temp.low = block & 0xFFFF;
temp.high = (block>>16) & 0xFF;
return (mstack_test(&temp) == -1)? 0 : 1;
}
void pmmngr_free_block(void* address)
{
// Calculate block
mstack block;
unsigned temp = (unsigned)address / PMMNGR_BLOCK_SIZE;
block.low = temp & 0xFFFF;
block.high = (temp>>16) & 0xFF;
// Push it
mstack_push (&block);
}
void pmmngr_free_blocks (unsigned base, unsigned size)
{
mstack start, end, i;
// 4k align
base /= PMMNGR_BLOCK_SIZE;
size /= PMMNGR_BLOCK_SIZE;
// Calculate blocks
start.low = base & 0xFFFF;
start.high = (base >> 16) & 0xFF;
end.low = (base + size) & 0xFFFF;
end.high = ((base + size)>>16) & 0xFF;
for (i.low = start.low, i.high = start.high; // i = start
i.low < end.low || i.high < end.high;) // i != end
{
// only push if block is used
if (mstack_test(&i) == -1) mstack_push(&i);
// increment i.high
if (i.low == 0xFFFF) {
i.low = 0; i.high++;
}
else i.low++;
}
}
void* pmmngr_alloc_block()
{
if (_mmngr_index == 0) return 0;// Out of memory
// pop a block
mstack block = mstack_pop();
// Calculate and return address;
void* address;
unsigned temp = block.low | (block.high<<16);
address = (void *)(temp * PMMNGR_BLOCK_SIZE);
return address;
}
void* pmmngr_alloc_blocks (unsigned blocks)
{
// Less than 2 blocks requested
if (blocks == 0) return 0;
if (blocks == 1) return pmmngr_alloc_block();
// Sort the stack for the next step
mstack_qsort(0, (int)_mmngr_index);
int i = (int) _mmngr_index-1; // i = counter
int l = 1; // l = number of consecutive blocks
unsigned temp; // temp = temporary storage
unsigned prev = _mmngr_memory_stack[i].low | (_mmngr_memory_stack[i].high<<16); --i;
// Search consecutive blocks
for (; i >=0; i--) {
temp = _mmngr_memory_stack[i].low | (_mmngr_memory_stack[i].high<<16);
if (temp == prev-1) l++;
else l = 1;
if (l == blocks) {
pmmngr_deinit_region (temp * PMMNGR_BLOCK_SIZE, blocks * PMMNGR_BLOCK_SIZE);
return (void*) (temp * PMMNGR_BLOCK_SIZE);
}
prev = temp;
}
return 0; // Could not find so many free blocks
}
// +==============================================+
// | GET DATA FUNCTIONS |
// +===================================== cta os =+
unsigned pmmngr_get_memory_size () {
return _mmngr_memory_size;
}
uint32_t pmmngr_get_block_count () {
unsigned pmmngr_get_block_count () {
return _mmngr_max_blocks;
}
uint32_t pmmngr_get_use_block_count () {
unsigned pmmngr_get_use_block_count () {
return _mmngr_used_blocks;
}
uint32_t pmmngr_get_free_block_count () {
unsigned pmmngr_get_free_block_count () {
return _mmngr_index;
}
uint32_t pmmngr_get_block_size () {
unsigned pmmngr_get_block_size () {
return PMMNGR_BLOCK_SIZE;
}
void pmmngr_paging_enable (byte b) {
uint32_t temp;
// +==============================================+
// | PAGING RELATED FUNCTIONS |
// +===================================== cta os =+
void pmmngr_paging_enable (unsigned char b) {
unsigned temp;
temp = read_cr0();
// Enable
@ -192,13 +343,7 @@ void pmmngr_paging_enable (byte b) {
write_cr0(temp);
}
byte pmmngr_is_paging () {
uint32_t temp = read_cr0();
unsigned char pmmngr_is_paging () {
unsigned temp = read_cr0();
return ((temp&0x80000000)>0);
}
mstack* pmmngr_get_stack_addr()
{
return _mmngr_memory_stack;
}

View File

@ -1,33 +1,47 @@
#ifndef _MMNGR_PHYS_H
#define _MMNGR_PHYS_H
#include <stdint.h>
#include <system.h>
#define pmmngr_load_PDBR(addr) write_cr3(addr)
#define pmmngr_get_PDBR() read_cr3()
// physical address
typedef unsigned physical_addr;
extern uint32_t read_cr0();
extern uint32_t read_cr3();
extern void write_cr0(uint32_t data);
extern void write_cr3(uint32_t data);
extern void pmmngr_free_block(void* address); // releases a memory block
extern void* pmmngr_alloc_block (); // allocates a single memory block
extern void pmmngr_init (size_t memSize, uint32_t stack); // initialize the physical memory manager
extern void pmmngr_init_region (physical_addr base, size_t size); // enables a physical memory region for use
extern void pmmngr_deinit_region (physical_addr base, size_t size); // disables a physical memory region as in use (unuseable)
extern size_t pmmngr_get_memory_size (); // returns amount of physical memory the manager is set to use
extern uint32_t pmmngr_get_use_block_count (); // returns number of blocks currently in use
extern uint32_t pmmngr_get_free_block_count (); // returns number of blocks not in use
extern uint32_t pmmngr_get_block_count (); // returns number of memory blocks
extern uint32_t pmmngr_get_block_size (); // returns default memory block size in bytes
extern void pmmngr_paging_enable (byte b); // enable or disable paging
extern byte pmmngr_is_paging (); // test if paging is enabled
struct memory_stack_entry{
unsigned short low;
unsigned char high;
} __attribute__ ((__packed__));
typedef struct memory_stack_entry mstack;
// CR registers r/w operations
extern unsigned read_cr0();
extern unsigned read_cr3();
extern void write_cr0(unsigned data);
extern void write_cr3(unsigned data);
// Free/Alloc memory block(s)
extern void pmmngr_free_block(void* address);
extern void pmmngr_free_blocks(unsigned base, unsigned size);
extern void* pmmngr_alloc_block ();
extern void* pmmngr_alloc_blocks (unsigned blocks);
// De/Initialisation routines
extern void pmmngr_init (unsigned memSize, unsigned stack);
extern void pmmngr_init_region (unsigned base, unsigned size);
extern void pmmngr_deinit_region (unsigned base, unsigned size);
// Useful information
extern unsigned pmmngr_get_memory_size (); // returns amount of physical memory the manager is set to use
extern unsigned pmmngr_get_use_block_count (); // returns number of blocks currently in use
extern unsigned pmmngr_get_free_block_count (); // returns number of blocks not in use
extern unsigned pmmngr_get_block_count (); // returns number of memory blocks
extern unsigned pmmngr_get_block_size (); // returns default memory block size in unsigned chars
extern unsigned char pmmngr_test_block (unsigned block);
// Paging
extern void pmmngr_paging_enable (unsigned char b); // enable or disable paging
extern unsigned char pmmngr_is_paging (); // test if paging is enabled
extern void print_stack();
extern byte pmmngr_test_block (uint32_t block);
#endif

140
SysCore/memory/mmngr_vi.c Normal file
View File

@ -0,0 +1,140 @@
// +==============================================+
// | HEADERS |
// +===================================== cta os =+
#include "mmngr_vi.h"
#include "mmngr_ph.h"
// +==============================================+
// | DEFINITIONS |
// +===================================== cta os =+
#define PAGE_SIZE 4096
#define PTABLE_ADDR_SPACE_SIZE 0x400000
#define DTABLE_ADDR_SPACE_SIZE 0xffffffff
pdirectory* _current_directory;
unsigned _current_page_directory_base_register;
extern unsigned char *memset (unsigned char *dest, unsigned char val, int count);
extern char getch();
// +==============================================+
// | PAGE FUNCTIONS |
// +===================================== cta os =+
unsigned char vmmngr_alloc_page (pt_entry* entry)
{
void* p = pmmngr_alloc_block ();
if (!p) return 0;
pt_entry_set_frame(entry, (unsigned)p);
pt_entry_add_attrib (entry, _I86_PTE_PRESENT);
return 1;
}
void vmmngr_free_page (pt_entry* entry)
{
void* p = (void*) pt_entry_get_frame(*entry);
if (p) pmmngr_free_block (p);
pt_entry_del_attrib (entry, _I86_PTE_PRESENT);
}
// +==============================================+
// | PAGE TABLE FUNCTIONS |
// +===================================== cta os =+
inline void vmmngr_ptable_clear(ptable* p)
{
if(p) memset ((unsigned char*)p, 0, sizeof(ptable));
}
inline unsigned vmmngr_ptable_virt_to_index (unsigned addr)
{
return (addr >= PTABLE_ADDR_SPACE_SIZE) ? 0 : addr/PAGE_SIZE;
}
inline pt_entry* vmmngr_ptable_lookup_entry (ptable* p, unsigned addr)
{
if (p) return &p->m_entries[vmmngr_ptable_virt_to_index(addr)];
return 0;
}
// +==============================================+
// | PAGE DIRECTORY FUNCTIONS |
// +===================================== cta os =+
inline void vmmngr_pdirectory_clear(pdirectory* dir)
{
if(dir) memset ((unsigned char*)dir, 0, sizeof(pdirectory));
}
inline unsigned vmmngr_pdirectory_virt_to_index (unsigned addr)
{
return (addr > DTABLE_ADDR_SPACE_SIZE) ? 0 : addr/PAGE_SIZE;
}
inline pd_entry* vmmngr_pdirectory_lookup_entry (pdirectory* dir, unsigned addr)
{
if (dir) return &dir->m_entries[vmmngr_ptable_virt_to_index(addr)];
return 0;
}
// +==============================================+
// | VIRTUAL MEMORY MANAGER |
// +===================================== cta os =+
inline unsigned char vmmngr_switch_pdirectory (pdirectory* dir)
{
if (!dir) return 0;
_current_directory = dir;
write_cr3 (_current_page_directory_base_register);
return 1;
}
pdirectory* vmmngr_get_directory() {
return _current_directory;
}
void vmmngr_initialize()
{
// Allocate default page table
ptable* table = (ptable*) pmmngr_alloc_block();
if (!table) return;
// Clear page table
vmmngr_ptable_clear(table);
// Identity map the first page table
int i, frame;
for (i = 0, frame = 0; i < 1024; i++, frame += 4096)
{
// Create a new page
pt_entry page = 0;
pt_entry_add_attrib (&page, _I86_PTE_PRESENT);
pt_entry_set_frame (&page, frame);
table->m_entries[vmmngr_ptable_virt_to_index(frame)] = page;
}
// Create default directory table
pdirectory* dir = (pdirectory*) pmmngr_alloc_blocks(3);
if (!dir) return;
// Clear directory table and set it as current
vmmngr_pdirectory_clear(dir);
// Get first entry in dir table and set it up to point to our table
pd_entry* entry = vmmngr_pdirectory_lookup_entry(dir, 0);
pd_entry_add_attrib (entry, _I86_PDE_PRESENT);
pd_entry_add_attrib (entry, _I86_PDE_WRITABLE);
pd_entry_set_frame (entry, (unsigned) table);
// Store current PDBR
_current_page_directory_base_register = (unsigned) &dir->m_entries;
// Switch to our page directory
vmmngr_switch_pdirectory (dir);
// Enable paging
pmmngr_paging_enable (1);
}

25
SysCore/memory/mmngr_vi.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __MEMORY_MANAGER_VIRTUAL__
#define __MEMORY_MANAGER_VIRTUAL__
#include "lib/pde.h"
#include "lib/pte.h"
#define PAGES_PER_TABLE 1024
#define PAGES_PER_DIR 1024
typedef unsigned virtual_address;
typedef struct {
pt_entry m_entries[PAGES_PER_TABLE];
} ptable ;
typedef struct {
pd_entry m_entries[PAGES_PER_DIR];
} pdirectory ;
//extern pdirectory* _current_directory;
extern void vmmngr_flush_tbl_entry (unsigned addr);
extern void vmmngr_initialize();
#endif

View File

@ -1,26 +0,0 @@
#include <pde.h>
void pt_entry_add_attrib (pt_entry* entry, unsigned mask) {
*entry |= mask;
}
void pt_entry_del_attrib (pt_entry* entry, unsigned mask) {
*entry &= ~mask;
}
void pt_entry_set_frame (pt_entry* entry, unsigned address) {
*entry &= ~_I86_PTE_FRAME;
*entry |= address & _I86_PTE_FRAME;
}
unsigned pt_entry_get_frame (pt_entry entry) {
return entry&_I86_PTE_FRAME;
}
unsigned char pt_entry_is_present (pt_entry entry) {
return ( (entry & _I86_PTE_PRESENT) > 0 );
}
unsigned char pt_entry_is_writable (pt_entry entry) {
return ( (entry & _I86_PTE_WRITABLE) > 0 );
}

View File

@ -1,27 +0,0 @@
#ifndef __PAGE_DIRECTORY_ENTRY_
#define __PAGE_DIRECTORY_ENTRY_
enum __PAGE_FLAGS {
_I86_PTE_PRESENT = 1,
_I86_PTE_WRITABLE = 2,
_I86_PTE_USER = 4,
_I86_PTE_WRITETHROUGH = 8,
_I86_PTE_NOT_CACHEABLE = 0x10,
_I86_PTE_ACCESSED = 0x20,
_I86_PTE_DIRTY = 0x40,
_I86_PTE_PAT = 0x80,
_I86_PTE_CPU_GLOBAL = 0x100,
_I86_PTE_LV4_GLOBAL = 0x200,
_I86_PTE_FRAME = 0x7FFFF000
};
typedef unsigned pt_entry;
extern void pt_entry_add_attrib (pt_entry* entry, unsigned mask);
extern void pt_entry_del_attrib (pt_entry* entry, unsigned mask);
extern void pt_entry_set_frame (pt_entry* entry, unsigned address);
extern unsigned pt_entry_get_frame (pt_entry entry);
extern unsigned char pt_entry_is_present (pt_entry entry);
extern unsigned char pt_entry_is_writable (pt_entry entry);
#endif