summaryrefslogtreecommitdiff
path: root/src/kernel/libs/page.c
blob: 6f1dd7ca0ce9285388b52714bfae9003d12ec277 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <printf.h>
#include <paging.h>
#include <stdint.h>
#include <libc.h> 

void debug_print_memory() {
  struct memory_table *memtable = (struct memory_table *)&_meminfo_loc; 
  printf(" __________________________________________________________________________\n");
  printf("| type\tstart\t\t\tend\t\t\tsize\t\t   |\n");
  printf("|--------------------------------------------------------------------------|\n");
  for(unsigned int i = 0; memtable[i].length > 0; i++) {
    printf("| %u %u\t0x%p\t0x%p\t0x%p |\n", memtable[i].type, memtable[i].ACPI, memtable[i].base, (memtable[i].base + memtable[i].length), memtable[i].length);
  }
  printf("----------------------------------------------------------------------------\n");
}


//uses buddy system allocation
void init_memory() {
  struct memory_table *memtable = (struct memory_table *)&_meminfo_loc;
  struct phys_map *map = (struct phys_map*)0x200000;
  uintptr_t onpage = 0x200000;
  unsigned int i, x, buddy_size, buddy_bitsize, prev_buddy_bsize;
  uint64_t *buddy_ptr;
  
  map_page((void*)0x200000, (void*)0x200000, PAGE_SIZE_2M);
  void *next_page = (void *)onpage + 0x200000;
  // at this point, we are declaring our header and kernel itself as free (so don't forget to fix that!) 
  
  for(i = 0; memtable[i].length > 0; i++) {
    if((memtable[i].type == MEM_AVAILABLE) && (memtable[i].ACPI & 1)) {
     
      map->chunk_start = (void*)memtable[i].base;
      map->chunk_size = memtable[i].length;
      buddy_ptr = (void*)&map->buddies;


      for(x = 0; x < 8; x++) {

        buddy_bitsize = memtable[i].length / (0x1000 * (1 << x));
        buddy_size = ceil(buddy_bitsize / (float)8);
      
        if((void *)buddy_ptr + buddy_size >= next_page) {
          map_page(next_page, next_page, PAGE_SIZE_2M);
          next_page += 0x200000;
        }

        bzero(buddy_ptr, buddy_size); //meant to be /8?

        if((buddy_bitsize * 2) != prev_buddy_bsize) {
          buddy_ptr[-1] |= (1 << ((prev_buddy_bsize % 8) - 1));
        }

        buddy_ptr += buddy_size;

        prev_buddy_bsize = buddy_bitsize;

      }
      map->map_size = buddy_ptr - (uint64_t*)map;
      map = (struct phys_map *)map + map->map_size;

      if((void *)map + 24 >= next_page) {
        map_page(next_page, next_page, PAGE_SIZE_2M);
        next_page += 0x200000;
      }
    } 
  }
}

//TODO this function was deleted due to it being wrong. 
//I'll create it once I have the physical paging prerequisite set up. 
void create_pagetable_stage2(uint64_t free_mem) {
}


/**
 * BIG TODO:
 * Paging turned out to be simpler then I thought. I've temporarily fixed the code, but needs to be rewritten/simplified.
 * Let's get rid of those nasty GOTOs if we can.
 * Also, once we get physical memory allocator up and running, impliment that in this function.
**/

bool map_page(void *virtual_addr, void *physical_addr, uint8_t size) {
  //printf("map page called\n");
  uintptr_t va_ptr = (uintptr_t)virtual_addr;
  uintptr_t pa_ptr = (uintptr_t)physical_addr;
  if((va_ptr % (1 << size)) || (pa_ptr % (1 << size))) {
    return 0; 
  }
  page_table *table = (page_table *)PAGEMAP_LOCATION;
  int pte_i = (va_ptr >> 12) & 0x1ff;
  int pde_i = (va_ptr >> 21) & 0x1ff;
  int pdpe_i = (va_ptr >> 30) & 0x1ff;
  int pml4e_i = (va_ptr >> 39) & 0x1ff;

  if(table->pml4e[pml4e_i].present) {
    if(table->pml4e[pml4e_i].base_ptr != (uintptr_t)&table->pdpe[pdpe_i] >> 12) goto error;
    if(table->pdpe[pdpe_i].present) {
      if(size == PAGE_SIZE_1G) {
        if(table->pdpe[pdpe_i].base_ptr == (uintptr_t)pa_ptr >> 30 & 0x1ff)
          return true;
        goto error;
      }
      if(table->pdpe[pdpe_i].base_ptr != (uintptr_t)&table->pde[pde_i] >> 12) goto error;

      if(table->pde[pde_i].present) { 
        if(size == PAGE_SIZE_2M) {
          if(table->pde[pde_i].base_ptr == (uintptr_t)pa_ptr >> 21 & 0x1ff)
            return true;
          goto error;
        }
        if(table->pde[pde_i].base_ptr != (uintptr_t)&table->pte[pte_i] >> 12) goto error;
        if(table->pte[pte_i].present) {
          if(table->pte[pte_i].base_ptr != ((pa_ptr >> 12) & 0x1ff)) goto error;
          return true;
        }
        else goto mod_page_pte;
      }
      else goto mod_page_pde;
    }
    else goto mod_page_pdpe;
  }
  else {
    table->pml4e[pml4e_i].base_ptr = (uintptr_t)&table->pdpe[pdpe_i] >> 12;
    table->pdpe[pml4e_i].read_write = 1;
    table->pml4e[pml4e_i].present = 1;
mod_page_pdpe:
    table->pdpe[pdpe_i].read_write = 1;
    //TODO you just found out things are a lot more simple then you thought!
    if(size == PAGE_SIZE_1G) {
      table->pdpe[pdpe_i].size = 1;
      table->pdpe[pdpe_i].base_ptr = pa_ptr >> 12;
      table->pdpe[pdpe_i].present = 1;
      return true;
    }
    table->pdpe[pdpe_i].base_ptr = (uintptr_t)&table->pde[pde_i] >> 12;
    table->pdpe[pdpe_i].present = 1;
mod_page_pde:
    table->pde[pde_i].read_write = 1;
    if(size == PAGE_SIZE_2M) {
      table->pde[pde_i].size = 1;
      table->pde[pde_i].base_ptr = pa_ptr >> 12;
      table->pde[pde_i].present = 1;
      return true;
    }
    table->pde[pde_i].base_ptr = (uintptr_t)&table->pte[pte_i] >> 12;
    table->pde[pde_i].present = 1;
mod_page_pte:
    table->pte[pte_i].base_ptr = pa_ptr >> 12;
    table->pte[pte_i].read_write = 1;
    table->pte[pte_i].present = 1;
    return true;
  }
error:
  printf("Page allocation error!\n");
  return false;
}