Paging isnt too hard to setup, you (assuming you are using default 4k pages) setup a page directory with 1024 entries. These entries each contain a pointer and page flags, each entry in the directory points to a page table. Page tables are almost exactly the same as a directory, except the entries point to pages, which are basically imaginary 4k blocks of physical memory.
The logical address you use when you use paging is
10 bits page table entry in directory
10 bits page entry in table
12 bits offset in page
...wich the cpu turns into another logical address used by segmentation to finally make a physical address.
If your segments use a flat address area (0-4gb addresses, 2 segments code and data) then you can pretend segments don't exist (just remeber to set ds and ss at least once).
The entires in the page tables and directory contain an address and flags.
format:
Code: Select all
bits purpose
12-31 address
11-9 available for whatever you want to use here
8 global bit -ignored
7 page size- 0 for 4k
6 reserved leave 0
5 acessed, use to identify a page that has been unused since last time you checked
4 disables cach, leave 0
3 write through? leave 0
2 1 for user, 0 for supervisor (1 keeps userland from modifing)
1 r/w 1 for write, 0 is read only
0 present, if this is unset this page loaded your os hasnt allocated a place in physical ram and mapped it to this page yet- you load the page from hard drive to a free address you havent used and set the address and present parts.
When the present bit is not set you can put whatever in the rest of the entry- its available for programmer use (store offset in page file that contains the data for this page etc).
Here is some code, its not complete, it just sets pages for every page in a 4gb address space flat with no page file(all pages are loaded- if you access memory thats not installed the data stored there is always 0).
Code: Select all
;page directory list tables 1024 entries * 4 bytes = 4096 bytes 1000h
;137000-138000
K_PAGE_DIRS equ 137000h
K_PAGE_DIRS_MAX equ 1024
K_PAGE_DIRS_END equ 138000h
;page tables 1024 tables * 1024 entries * 4 bytes = 4,194,304 bytes 40000h
;138000-178000
K_PAGE_TABLES equ 138000h
K_PAGE_TABLES_END equ 178000h
K_PAGE_TABLES_MAX equ 1024
use32
;setup pages
call MAKE_KERNEL_PAGES
;enabling paging
mov eax, K_PAGE_DIRS
mov cr3, eax
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
Code: Select all
;creates the kernel page directory and tables
use32
MAKE_KERNEL_PAGES:
;save all regs
pusha
;set start addresses
mov eax, K_PAGE_DIRS
mov ebx, K_PAGE_TABLES
mov edx, 0
;create directory entries
.kpage_loopdir:
;save table base pointer
push ebx
or ebx, 3
mov [ds:eax], ebx
pop ebx
;create table entries
mov ecx, 0
.kpage_looptable:
;store directory entry pointer
push eax
;get table entry pointer
mov eax, ecx
add eax, ebx
;save entry
push edx
or edx, 3
mov [ds:eax], edx
pop edx
;restore directory entry pointer
pop eax
;increment table entry pointer
add ecx, 4
;increment physical address
add edx, 4096
;if not at end of table continue
cmp ecx, 4096
jl .kpage_looptable
;increment directory entry pointer
add eax, 4
;increment page table pointer
add ebx, 4096
;if not at end of directory, continue
cmp eax, K_PAGE_DIRS_END
jl .kpage_loopdir
;restore regs and return to caller
popa
ret
That will get you started but you would need to avoid just setting them all to present, and use a method for showing where you have and havent allocated memory yet. I use a "bitmap" approach with 4mb granularity, each of my blocks (units of allocation) is 1000 pages large. Its so I can use all page size extensions (4k, 2m, and 4m) without using separate allocation structures. Its not perfect, as I am still a os dev newb. But that should get you started with atleast a working example.
ps: oh yea, make sure your page directory and tables are on 4kb boundries- ie the addresses end in xxx000h (4096 = 1000h)