nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
paging.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stddef.h>
6 #include <stdarg.h>
7 #include <stdint.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <assert.h>
11 
12 #include <arch.h>
13 #include <debug.h>
14 #include <paging.h>
15 #include <initm.h>
16 
17 #include <list.h>
18 #include <cpu_node.h>
19 #include <zone.h>
20 #include <page_frame.h>
21 
22 #include <segment.h> /* For the IO_BITMAP_SIZE */
23 #include <x86.h>
24 
25 struct pgde *s_rpgd;
26 
31 static inline int reset_table(void *initm,
32  struct pgde *pgd, unsigned long pma, unsigned long vma,
33  size_t size)
34 {
35  int pgt_idx;
36  int page_idx;
37  struct pgte *pgt;
38  uint32_t tmp;
39  register int i;
40 
41  TO_IDX(vma, pgt_idx, page_idx);
42 
43  while (size) {
44  tmp = sysconf(_SC_PAGESIZE);
45 
46  if (!pgd[pgt_idx].p) {
47  tmp *= (NR_PAGES - page_idx);
48  if (size < tmp) {
49  break;
50  }
51  size -= tmp;
52  pgt_idx++;
53  page_idx = 0;
54  continue;
55  }
56 
57  pgt = (struct pgte*)(pgd[pgt_idx].pt_base * tmp);
58  pgt = initm_find_vma(pgt);
59 
60  while (page_idx < NR_PAGES && size >= tmp) {
61  pgt[page_idx].p = 0;
62  pgt[page_idx].page_base = 0;
63  page_idx++;
64  size -= tmp;
65  }
66 
67  for (i = 0; i < NR_PAGES && !pgt[i].p; i++);
68  if (i == NR_PAGES) {
69  pgd[pgt_idx].p = 0;
70  pgd[pgt_idx].pt_base = 0;
71 
72  initm_free(initm, (char*)pgt);
73  }
74 
75  if (page_idx == NR_PAGES) {
76  pgt_idx++;
77  page_idx = 0;
78  }
79  }
80 
81  reload_cr3();
82  return 0;
83 }
84 
85 static inline struct pgte *get_pgt(void *initm, struct pgde *pgd, int idx)
86 {
87  struct pgte *pgt;
88  uint32_t pagesize;
89 
90  pagesize = sysconf(_SC_PAGESIZE);
91  if (pgd[idx].p) {
92  pgt = (struct pgte *)(pgd[idx].pt_base * pagesize);
93  dbg_printf("Allocated PGT: %p\n", pgt);
94  return pgt;
95  }
96 
97  pgt = (struct pgte *)initm_alloc(initm);
98  if (!pgt) {
99  dbg_printf("Failed to allocate pgt\n");
100  return NULL;
101  }
102 
103  memset(pgt, 0, pagesize);
104  pgd[idx].p = 1;
105  pgd[idx].rw = 1;
106  pgd[idx].pt_base = (uint32_t)pgt / pagesize;
107 
108  return pgt;
109 }
110 
111 static inline int setup_table(void *initm, struct pgde *pgd,
112  uint32_t pma, uint32_t vma, ssize_t size)
113 {
114  int pgt_idx;
115  int page_idx;
116  struct pgte *pgt;
117  uint32_t pagesize;
118 
119  pagesize = sysconf(_SC_PAGESIZE);
120 
121  pma /= pagesize;
122  size /= pagesize;
123  TO_IDX(vma, pgt_idx, page_idx);
124 
125  pgt = get_pgt(initm, pgd, pgt_idx);
126  if (!pgt) {
127  return -EINVAL;
128  }
129 
130  while (size > 0) {
131  if (pgt[page_idx].p) {
132  return -EFAULT;
133  }
134 
135  pgt[page_idx].p = 1;
136  pgt[page_idx].rw = 1;
137  pgt[page_idx].page_base = pma;
138 
139  pma++;
140  size--;
141  page_idx++;
142 
143  if (page_idx == NR_PAGES) {
144  pgt_idx++;
145 
146  if (pgt_idx == NR_TABLES) {
147  break;
148  }
149 
150  pgt = get_pgt(initm, pgd, pgt_idx);
151  if (!pgt) {
152  return -EINVAL;
153  }
154 
155  page_idx = 0;
156  }
157  }
158 
159  return 0;
160 }
161 
162 int vm_init(struct memmap *map, uint32_t kvma)
163 {
164  struct pgde *pgd;
165  int ret;
166 
167  pgd = (struct pgde *)initm_alloc(map->initm);
168  if (!pgd) {
169  return -ENOMEM;
170  }
171 
172  memset(pgd, 0, sysconf(_SC_PAGESIZE));
173 
179  ret = setup_table(map->initm, pgd, 0x0, 0x0, 1 << 20);
180  if (ret < 0) {
181  return ret;
182  }
183 
188  ret = setup_table(map->initm, pgd,
189  (uint32_t)map->env,
190  (uint32_t)kvma,
191  map->env_size + map->kernel_size +
192  map->initm_size + map->heap_size);
193  if (ret < 0) {
194  return ret;
195  }
196 
201  ret = setup_table(map->initm, pgd,
202  (uint32_t)map->env + map->env_size + map->kernel_size +
203  map->initm_size + map->heap_size,
204  0xFFFFFFFF - (map->tcb_size + map->stack_size) + 1 - (0x01 << 20),
205  map->tcb_size + map->stack_size);
206 
215  ret = setup_table(map->initm, pgd,
216  (uint32_t)map->env, (uint32_t)map->env,
217  map->env_size + map->kernel_size +
218  map->initm_size + map->heap_size +
219  map->stack_size + map->tcb_size
220  );
221  if (ret < 0) {
222  return ret;
223  }
224 
231  load_cr3(pgd);
232  vm_enable();
233 
234  return 0;
235 }
236 
241 int vm_init_done(struct memmap *map, unsigned long kpma)
242 {
243  struct pgde *pgd;
244  int ret;
245 
246  pgd = read_cr3();
247  if (!pgd) {
248  return -EFAULT;
249  }
250 
251  pgd = initm_find_vma(pgd);
252  reset_table(map->initm, pgd,
253  kpma, kpma,
254  map->env_size + map->kernel_size +
255  map->initm_size + map->heap_size +
256  map->stack_size + map->tcb_size);
257 
262  s_rpgd = initm_alloc(map->initm);
263  if (!s_rpgd) {
264  return -ENOMEM;
265  }
266 
267  memset(s_rpgd, 0, sysconf(_SC_PAGESIZE));
268 
273  ret = setup_table(map->initm, s_rpgd,
274  (uint32_t)0, (uint32_t)0, 1 << 20);
275  if (ret < 0) {
276  return ret;
277  }
278 
283  ret = setup_table(map->initm, s_rpgd,
284  (uint32_t)map->env,
285  (uint32_t)kpma,
286  map->env_size + map->kernel_size +
287  map->initm_size + map->heap_size);
288  if (ret < 0) {
289  return ret;
290  }
291 
296  ret = setup_table(map->initm, s_rpgd,
297  (0xFFFFFFFF - (map->tcb_size + map->stack_size)) + 1 - (0x01 << 20),
298  (uint32_t)map->env + map->env_size + map->kernel_size +
299  map->initm_size + map->heap_size,
300  map->tcb_size + map->stack_size);
301 
302  return 0;
303 }
304 
305 void vm_enable(void)
306 {
307  register unsigned int cr0;
308 
313  asm volatile ("movl %%cr0, %0":"=r"(cr0):);
314  cr0 |= 0x80000000;
315  asm volatile ("movl %0, %%cr0"::"r"(cr0));
316 }
317 
318 int vm_is_enabled(void)
319 {
320  register unsigned int cr0;
321 
322  asm volatile ("mov %%cr0, %0":"=r"(cr0):);
323  return !!(cr0 & 0x80000000);
324 }
325 
326 int vm_frame_init(int memcnt, int membase[], int memsize[])
327 {
328  struct node *node;
329  int i;
330  enum zone_type zone[] = {
331  ZONE_BASE,
332  ZONE_NORMAL,
333  ZONE_HIMEM,
334  };
335 
336  if (memcnt > ZONE_HIMEM) {
337  return -EINVAL;
338  }
339 
340  node = cpu_node_create(0);
341  for (i = 0; i < memcnt; i++) {
342  if (!memsize[i]) {
343  continue;
344  }
345 
350  if (create_zone(node, zone[i], membase[i], memsize[i]) < 0) {
351  continue;
352  }
353 
354  dbg_printf("ZONE[%d] is created\n", zone[i]);
355  }
356 
361  i = create_zone(node, ZONE_SYSTEM, 0, 0);
362  assert(i == 0 && "Failed to create ZONE_SYSTEM");
363  dbg_printf("ZONE[%d] is created\n", ZONE_SYSTEM);
364 
365  return 0;
366 }
367 
368 void *vm_rpgd()
369 {
370  return s_rpgd;
371 }
372 
373 /* End of a file */