summaryrefslogtreecommitdiff
path: root/kernel/source/app-memory.cpp
blob: cca1359e5dc63839c6bdeb4debb900adcbf98a96 (plain) (blame)
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <hilbert/kernel/app-memory.hpp>
#include <hilbert/kernel/paging.hpp>
#include <hilbert/kernel/panic.hpp>

namespace hilbert::kernel {

  app_memory::app_memory() {

    uint64_t p3_paddr;
    paging::map_new_kernel_page(p3, p3_paddr);
    paging::map_new_kernel_page(p4, p4_paddr);

    for (int i = 0; i < 512; ++i) {
      p4[i] = 0;
      p3[i] = 0;
      p2s[i] = 0;
      p1s[i] = 0;
      pram_pages_to_free_on_exit[i] = 0;
    }

    p4[0] = paging::encode_pte(p3_paddr, true, true, true);
    p4[511] = paging::kernel_p4e;

  }

  app_memory::~app_memory() {

    //first we see if the p2s exist
    for (int p3i = 0; p3i < 512; ++p3i)
      if (p3[p3i]) {

        //now we see if the p1s under this p2 exist
        for (int p2i = 0; p2i < 512; ++p2i)
          if (p2s[p3i][p2i]) {

            //we see if the pages under this p1 need to be freed
            for (int p1i = 0; p1i < 512; ++p1i)
              if (pram_pages_to_free_on_exit[p3i][p2i][p1i])
                paging::free_pram_page(
                  paging::pte_to_paddr(p1s[p3i][p2i][p1i]));

            //we free the p1 and the pram list
            paging::free_pram_page(paging::pte_to_paddr(p2s[p3i][p2i]));
            paging::unmap_kernel_page((uint64_t)p1s[p3i][p2i]);
            delete[] pram_pages_to_free_on_exit[p3i][p2i];

          }

        //free the p2, the p1 list, and the pram list list
        paging::free_pram_page(paging::pte_to_paddr(p3[p3i]));
        paging::unmap_kernel_page((uint64_t)p2s[p3i]);
        delete[] p1s[p3i];
        delete[] pram_pages_to_free_on_exit[p3i];

      }

    //finally, we free the p3 and the p4
    paging::free_pram_page(paging::pte_to_paddr(p4[0]));
    paging::unmap_kernel_page((uint64_t)p3);
    paging::free_pram_page(p4_paddr);
    paging::unmap_kernel_page((uint64_t)p4);

  }

  void app_memory::map_page(uint64_t vaddr, uint64_t paddr,
    bool write, bool execute, bool free_pram_on_exit) {

    int p1i = (vaddr >> 12) & 511;
    int p2i = (vaddr >> 21) & 511;
    int p3i = (vaddr >> 30) & 511;

    if (p2s[p3i] == 0) {
      uint64_t new_p2_paddr;
      paging::map_new_kernel_page(p2s[p3i], new_p2_paddr);
      p1s[p3i] = new v_page_table[512];
      pram_pages_to_free_on_exit[p3i] = new bool *[512];
      for (int i = 0; i < 512; ++i) {
        p2s[p3i][i] = 0;
        p1s[p3i][i] = 0;
        pram_pages_to_free_on_exit[p3i][i] = 0;
      }
      p3[p3i] = paging::encode_pte(new_p2_paddr, true, true, true);
    }

    if (p1s[p3i][p2i] == 0) {
      uint64_t new_p1_paddr;
      paging::map_new_kernel_page(p1s[p3i][p2i], new_p1_paddr);
      pram_pages_to_free_on_exit[p3i][p2i] = new bool[512];
      for (int i = 0; i < 512; ++i) {
        p1s[p3i][p2i][i] = 0;
        pram_pages_to_free_on_exit[p3i][p2i][i] = false;
      }
      p2s[p3i][p2i] = paging::encode_pte(new_p1_paddr, true, true, true);
    }

    p1s[p3i][p2i][p1i] = paging::encode_pte(paddr, true, write, execute);
    pram_pages_to_free_on_exit[p3i][p2i][p1i] = free_pram_on_exit;

  }

  void app_memory::unmap_page(uint64_t vaddr) {
    int p1i = (vaddr >> 12) & 511;
    int p2i = (vaddr >> 21) & 511;
    int p3i = (vaddr >> 30) & 511;
    if (pram_pages_to_free_on_exit[p3i][p2i][p1i]) {
      pram_pages_to_free_on_exit[p3i][p2i][p1i] = false;
      paging::free_pram_page(paging::pte_to_paddr(p1s[p3i][p2i][p1i]));
    }
    p1s[p3i][p2i][p1i] = 0;
  }

  bool app_memory::valid_to_read(
    uint64_t vaddr_start, uint64_t vaddr_end, bool and_write) const {
    if (vaddr_start > vaddr_end || vaddr_end > 0x8000000000)
      return false;
    vaddr_start = (vaddr_start / 4096) * 4096;
    vaddr_end = (((vaddr_end - 1) / 4096) + 1) * 4096;
    for (uint64_t vaddr = vaddr_start; vaddr < vaddr_end; ++vaddr) {
      int p1i = (vaddr >> 12) & 511;
      int p2i = (vaddr >> 21) & 511;
      int p3i = (vaddr >> 30) & 511;
      if (!p1s[p3i] || !p1s[p3i][p2i] || !(and_write
            ? (p1s[p3i][p2i][p1i] & 0x1) : p1s[p3i][p2i][p1i]))
        return false;
    }
    return true;
  }

  uint64_t app_memory::get_free_vaddr_pages(uint64_t count) {
    uint64_t vaddr = 0x1000;
    uint64_t run = 0;
    while (true) {
      if (run == count)
        return vaddr;
      if (vaddr + (run + 1) * 4096 > 0x4000000000)
        //TODO: handle out of virtual memory
        panic(0x9af5e6);
      if (valid_to_read(vaddr + run * 4096, vaddr + (run + 1) * 4096, false)) {
        vaddr += (run + 1) * 4096;
        run = 0;
      }
      else
        ++run;
    }
  }

  uint64_t app_memory::map_new_stack() {
    for (uint64_t base_vaddr = 0x4000000000;
         base_vaddr < 0x8000000000; base_vaddr += 0x1000000)
      if (!valid_to_read(base_vaddr + 4096, base_vaddr + 8192, false)) {

        for (uint64_t vaddr = base_vaddr + 4096;
             vaddr < base_vaddr + 0x1000000; vaddr += 4096) {

          uint8_t *kvaddr;
          uint64_t paddr;
          paging::map_new_kernel_page(kvaddr, paddr);
          for (int i = 0; i < 4096; ++i)
            kvaddr[i] = 0;
          paging::unmap_kernel_page(kvaddr);
          map_page(vaddr, paddr, true, false, true);

        }
        return base_vaddr + 0x1000000;

      }
    //TODO: handle out of stacks
    panic(0x9af5e6);

  }

  void app_memory::unmap_stack(uint64_t top) {
    for (uint64_t vaddr = top - 0xfff000; vaddr < top; vaddr += 4096)
      unmap_page(vaddr);
  }

  uint64_t app_memory::count_mapped_vram_pages() const {
    uint64_t count = 0;
    for (int p3i = 0; p3i < 512; ++p3i)
      if (p3[p3i])
        for (int p2i = 0; p2i < 512; ++p2i)
          if (p2s[p3i][p2i])
            for (int p1i = 0; p1i < 512; ++p1i)
              if (p1s[p3i][p2i][p1i])
                ++count;
    return count;
  }

}