aboutsummaryrefslogtreecommitdiff
path: root/kernel/memory/paging/page.dats
blob: 2880c18c4966dd75d6d007c9814cfc987906cde6 (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
#define ATS_DYNLOADFLAG 0

#include "kernel/prelude/kernel_prelude.hats"

staload "./page.sats"
staload FR = "kernel/memory/frame.sats"
staload "./table.sats"

staload "lib/SATS/valid.sats"
staload "lib/DATS/valid.dats"

datatype table_level = 
  | Level4
  | Level3
  | Level2
  | Level1

fn start_address(page : page_t) : size_t = page.num * $FR.PAGE_SIZE

fn get_index(page: page_t,n : intLte(3)) = g1ofg0((page.num >> (27 - 9 * n)) land i2sz(511))

//NOTE: huge page handler not implemented
fn translate_page(page: page_t) : Valid $FR.frame_t = let
  fun loop{n : nat | n < 3}.<3-n>.(table : table_t n, count : int n) : Valid $FR.frame_t = let
    staload "./entry.sats"
    val index = get_index(page,count)
  in
    if index < ENTRY_COUNT then let
        val v = next_table(table,index)
      in
        if is_valid(v) then let
            val table_next = unwrap_valid(v)
          in
            if count < 2 then
              loop(table_next,succ(count))
            else(
              consume(table_next);
              frame
            ) where {
                val index = get_index(page,count+1)
                val frame = (if index < ENTRY_COUNT then pointed_frame(table_next[index]) else create_unvalid()) : Valid $FR.frame_t
              }
          end
        else (
          destroy_unvalid(v);
          println!("Unvalid table pointer encountered: ", count); 
          create_unvalid())
      end
    else (
      consume(table);
      println!("Table index too big");
      create_unvalid())
  end
in
  loop(get_P4(),0)
end

implement translate(virtual_addr) = let
  val offset = Ptr0_to_sz(virtual_addr) % i2sz($FR.PAGE_SIZE)
  val vframe = translate_page(containing_address(virtual_addr))
in
  if is_valid(vframe) then let
      val frame = unwrap_valid(vframe)
    in
      create_valid (sz_to_Ptr0(frame.num * $FR.PAGE_SIZE + offset))
    end
  else (
    destroy_unvalid(vframe);
    create_unvalid();
  )
end

implement containing_address(address) = (
  assertloc(address < ulint_to_Ptr0(0x0000800000000000ul) ||
            address >= ulint_to_Ptr0(0xFFFF800000000000ul));
  @{num = Ptr0_to_sz(address) / i2sz($FR.PAGE_SIZE)}
)

// TODO: implement and_then and or_else for valid (like in rust)
implement map_to{s}(page,frame,flags,size) = let
  staload "./entry.sats"
  fun loop{n : nat | n < 3}.<3-n>.(table : table_t n, count : int n, flags: &(@[entry_flag][s])) : void = let
    staload "lib/SATS/panic.sats"
    val index = get_index(page,count)
    val () = println!(index)
  in
    if index < ENTRY_COUNT then let
        val v = next_table_create(table,index)
      in
        if is_valid(v) then let
            val table_next = unwrap_valid(v)
          in
            if count < 2 then
              loop(table_next,succ(count),flags)
            else let
                val index = get_index(page,count+1)
              in
                if index < ENTRY_COUNT then (
                  assertloc(is_unused(table_next[index]));
                  table_next[index] := add_flag(create_entry(frame, flags,size),PRESENT);
                );
                consume(table_next);
              end
          end
        else (
          destroy_unvalid(v);
          panic("Could not create table"))
      end
    else (
      consume(table);
      println!("Table index too big"))
  end
in
  loop(get_P4(),0,flags)
end

implement map(page,flags,size) = map_to(page,$FR.allocate_frame(),flags,size)