]> pd.if.org Git - zos/blob - mem.h
add a readme with a public domain note
[zos] / mem.h
1 #ifndef MEM_H_
2 #define MEM_H_ 1
3
4 #include <stdint.h>
5 #include <stddef.h>
6
7 #include "multiboot.h"
8
9 typedef uintptr_t paddr_t;
10 typedef uintptr_t vaddr_t;
11
12 extern uintptr_t _kernel_end;
13 extern uintptr_t _kernel_vma;
14 extern uintptr_t _kernel_phys_end;
15 extern uintptr_t _kernel_size;
16 extern uintptr_t _asm_physmap;
17
18 extern void *bios_ebda;
19
20 /* These are in memx64.s */
21 extern void flush_tlb(void *va);
22 extern void switch_address_space(uintptr_t cr3);
23
24 void vmem_test();
25
26 /* map one physical page to a virtual address */
27 #define PHY2VIRTP(pa) ( (void *)(((paddr_t)pa) + memory.physmap) )
28 /* only works for the linear mapped physical memory */
29 #define VIRTP2PHY(va) ( (paddr_t)(((vaddr_t)(va)) - memory.physmap) )
30 #define KB(x) ((x) * (1<<10))
31 #define MB(x) ((x) * (1<<20))
32 #define GB(x) (((uint64_t)x) * (1ULL<<30))
33 #define TB(x) (((uint64_t)x) * (1ULL<<40))
34 uintptr_t mem_align(uintptr_t a, size_t alignment);
35
36 /*
37  * kernel is at 0xFFFFFFFF80000000 and up
38  * we will map in all physical memory below that
39  */
40
41 /* structure of physical frames */
42 struct frame {
43         struct frame *next;
44         void *paddr; /* the physical address of the frame */
45         struct frame *prev;
46         void *top, *base;
47         uint64_t magic;
48 };
49
50 /* a map of memory */
51 /* TODO fix these types.  maybe add a physvend */
52 struct memory {
53         void *kbase; /* at 0xFFFFFFFF00000000 */
54         void *kstack; /* grow down from -1 ? */
55         uintptr_t kend; /* virtual address of top of kernel */
56         uintptr_t kphysend; /* physical address of top of kernel */
57         uintptr_t phys_max; /* maximum (usable) physical address + 1 */
58         uintptr_t physmap; /* all physical memory is mapped starting here */
59         /* kbase + kernel size ?, then put dynamic kernel structures above that,
60          * growing toward the stack?
61          */ 
62 };
63
64 /* TODO keep track of the kernel virtual address of page, we could
65  * re-alloc it in the same spot
66  */
67 struct pstack {
68         paddr_t page_addr[510]; /* physical addresses of frames */
69         size_t pages; /* free pages in this stack frame */
70         struct pstack *next; /* address of next stack frame */
71 };
72
73 /*
74  * free a page:
75  * if there is no room in the stack, then
76  * set the phys.stack.next to the new page
77  * map the new page in at phys.stack
78  * then add to phys.stack.pages
79  * the physical address to the stack.pages
80  *
81  * get a page:
82  * if there are no pages free on the stack:
83  * map in the  phys.stack.next to phys.stack
84  * hand out the old page, which is on pages[free]
85  * 
86  * it's probably worth memoizing the virtual address
87  * of the exact place where the stack vm map page is stored
88  * in the page tables
89  */
90 extern struct memory memory;
91
92 /* physical memory manager */
93 struct phys {
94         struct frame *base;
95         struct frame *top;
96         size_t frame_size;
97         int64_t offset; /* paddr = vaddr + offset */
98         struct phys *next;
99
100         vaddr_t kmap; /* physical address of page table entry for *stack */
101         vaddr_t *page_map; /* temporary page map space */
102         struct pstack *stack; /* virtual address of top of page stack */
103         size_t free;    /* total number of free pages */
104
105 };
106 /*
107  * pa = va + pb - vb
108  * va = pa + vb - pb
109  */
110
111 extern struct memory memory;
112 extern struct phys phys;
113
114 /*
115  * ops:
116  * add - add a contiguous chunk of physical memory and a virtual address base.
117  * alloc - get a page of memory
118  * free  - free a page of memory
119  * tinyalloc - get a really small page, 256 bytes
120  * tinyfree  - 
121  */
122
123 /* TODO lazy setup of the memory block stack */
124 /* TODO modify phys_init to be "more core" to support
125  * discontiguous memory addresses
126  */
127
128 /* These don't have to be the same as the hardware paging, but
129  * it probably helps
130  */
131 /* Hmm, need to map in memory for this to work */
132 /*
133  * pa = va + pb - vb
134  * va = pa + vb - pb
135  */
136
137 uint64_t getcr3(); /* probably in assembly */
138
139 paddr_t create_addrspace(void);
140
141
142 void test_address(void *);
143 void phys_init(struct multiboot_info *mbi);
144 void mem_init();
145 paddr_t palloc();
146 void pfree(paddr_t vmem);
147 void *koalloc(size_t size);
148 void kofree(void *, size_t size);
149 void dumpostacks(int f, int t);
150
151 uint64_t makecr3(void *pml4) ;
152 void *virt2phys(void *vaddr) ;
153
154 extern uint64_t kernel_space; /* physical address of kernel space? */
155 #define MEM_KERNEL (kernel_space)
156 #define KERNEL_PML4 ((struct pml4t *)PHY2VIRTP(kernel_space))
157
158 extern paddr_t pci_start;
159
160 struct cr3 {
161         uint64_t reslow:3; /* should be cleared to zero */
162         uint64_t pwt:1;         /* page writethrough */
163         uint64_t pcd:1;         /* page cache disable */
164         uint64_t resmed:7;      /* clear to zero */
165         uint64_t addr:40;       /* pml4 page base physical address shifted right 12 */
166         uint64_t reshigh:12;    /* clear to zero */
167 };
168
169 /* TODO last bit (63) is actually a no-execute bit */
170 struct pml4e {
171         uint64_t present:1;
172         uint64_t rw:1;
173         uint64_t user:1;
174         uint64_t pwt:1;
175         uint64_t pcd:1;
176         uint64_t a:1;
177         uint64_t ign:1;
178         uint64_t mbz:2;
179         uint64_t avl:3;
180         uint64_t addr:40;       /* pml4 page base physical address shifted right 12 */
181         uint64_t reshigh:12;    /* clear to zero */
182 };
183
184 struct pdpe {
185         uint64_t present:1;
186         uint64_t rw:1;
187         uint64_t user:1;
188         uint64_t pwt:1;
189         uint64_t pcd:1;
190         uint64_t a:1;
191         uint64_t ign:1;
192         uint64_t ps:1; /* I think this is the PS bit: 0 for 4KB or 2MB, 1 for 1GB */
193         uint64_t mbz:1;
194         uint64_t avl:3;
195         uint64_t addr:40;       /* pml4 page base physical address shifted right 12 */
196         uint64_t reshigh:12;    /* clear to zero */
197 };
198
199 struct pde {
200         uint64_t present:1;
201         uint64_t rw:1;
202         uint64_t user:1;
203         uint64_t pwt:1;
204         uint64_t pcd:1;
205         uint64_t a:1;
206         uint64_t ign:1;
207         uint64_t ps:1; /* I think this is the PS bit: 0 for 4KB */
208         uint64_t mbz:1;
209         uint64_t avl:3;
210         uint64_t addr:40;       /* pml4 page base physical address shifted right 12 */
211         uint64_t reshigh:12;    /* clear to zero */
212 };
213
214 struct pte {
215         uint64_t present:1;
216         uint64_t rw:1;
217         uint64_t user:1;
218         uint64_t pwt:1;
219         uint64_t pcd:1;
220         uint64_t a:1;
221         uint64_t d:1;
222         uint64_t pat:1;
223         uint64_t g:1;
224         uint64_t avl:3;
225         uint64_t addr:40;       /* pml4 page base physical address shifted right 12 */
226         uint64_t reshigh:12;    /* clear to zero */
227 };
228
229 struct pml4t {
230         struct pml4e pml4e[512];
231 };
232
233 struct pdpt {
234         struct pdpe pdpe[512];
235 };
236
237 struct pdt {
238         struct pde pde[512];
239 };
240
241 struct pt {
242         struct pte pte[512];
243 };
244
245 struct vaddr_decode {
246         /* broken down virtual address */
247         int pml4offset, pdpoffset, pdoffset, ptoffset;
248         paddr_t offset; /* physical page offset */
249
250         struct pml4t *pml4t; /* pml4 base address */
251         paddr_t pml4_phys; /* pml4 physical base address */
252
253         struct pml4e pml4e; /* entry in page map level 4 */
254         /* at pml4 + 8 * pml4offset */
255
256         struct pdpe  pdpe; /* entry in page directory pointer table */
257         /* at virt(pml4e.addr) + 8 * pdpoffset */
258         /* does not exist unless pml4e.present */
259         /* pdpe.ps == 1 means 1 GB pages, and the next level doesn't exist */
260         /* offset = vaddr & 0x3fffffff, physical page = standard - offset */
261         
262         struct pde   pde; /* entry in page directory table */
263         /* at virt(pdpe.addr) + 8 * pdoffset */
264         /* does not exist unless pdpe.present */
265         /* pde.ps == 0 means 4 KB pages and the next level exists if present */
266         /* pds.ps == 1 means 2 MB pages, pts doesn't exist and
267          * offset = vaddr & 0x1fffff; i.e. low 21 bits
268          * physical page address = same mask minus offset bits
269          */
270         
271         struct pte   pte; /* entry in page table */
272         /* at virt(pde.addr) + 8 * ptoffset */
273         /* does not exist unless pde.present */
274         /* offset = vaddr & 0xfff; i.e. low 12 bits */
275         /* physical page address = pde.addr, or vaddr & 0xffffffffff000 */
276
277         struct pte      *pteptr; /* a pointer to the actual entry */
278
279         /* actual physical addresses */
280         paddr_t pdpt_phys;
281         paddr_t pdt_phys;
282         paddr_t pt_phys;
283
284         int present; /* physical address actually mapped */
285         paddr_t paddr; /* decoded physical address */
286         int level;
287         paddr_t page; /* physical address of page */
288         size_t pagesize;
289 };
290
291 void decode_vaddr(struct vaddr_decode *ds, uint64_t space, vaddr_t vaddr);
292 void print_decode(struct vaddr_decode *ds, uint64_t space, vaddr_t vaddr);
293
294 /* returns addr.  addr may be null in which case the function will allocate virtual space */
295 void *map_page(uint64_t space, vaddr_t addr, paddr_t pa, unsigned int flags);
296 void vmapz(uint64_t space, vaddr_t addr, size_t length, unsigned int flags);
297
298 #define PT_PRESENT 0x1
299 #define MEM_PCD (1<<4)
300 #define MEM_PWT (1<<3)
301 #define MEM_USER (1<<2)
302 #define MEM_RW (1<<1)
303 #define MAP_TRACE (1<<16)
304
305 #define MEM_NOCACHE (MEM_PCD | MEM_PWT)
306 #define MEM_MMIO (PT_PRESENT|MEM_NOCACHE|MEM_RW)
307 #define MEM_USERSPACE (MEM_USER | MEM_RW)
308
309 #if 0
310 typedef struct page {
311    u32int present    : 1;   // Page present in memory
312    u32int rw         : 1;   // Read-only if clear, readwrite if set
313    u32int user       : 1;   // Supervisor level only if clear
314    u32int accessed   : 1;   // Has the page been accessed since last refresh?
315    u32int dirty      : 1;   // Has the page been written to since last refresh?
316    u32int unused     : 7;   // Amalgamation of unused and reserved bits
317    u32int frame      : 20;  // Frame address (shifted right 12 bits)
318 } page_t;
319
320 #endif
321
322 struct bios_data_area {
323         uint16_t        comaddr[4];
324         uint16_t        lpt[3];
325         uint16_t        ebda; /* <<4 to get actual */
326 };
327
328 #endif