7-ps2_keyboard.md and 8-multitasking.md (#29)
[lunaix-os.git] / lunaix-os / kernel / mm / pmm.c
1 #include <lunaix/mm/pmm.h>
2 #include <lunaix/status.h>
3 #include <lunaix/mm/pagetable.h>
4 #include <lunaix/spike.h>
5
6 // This is a very large array...
7 static struct pp_struct pm_table[PM_BMP_MAX_SIZE];
8 export_symbol(debug, pmm, pm_table);
9
10 static ptr_t max_pg;
11 export_symbol(debug, pmm, max_pg);
12
13 void
14 pmm_mark_page_free(ptr_t ppn)
15 {
16     if ((pm_table[ppn].attr & PP_FGLOCKED)) {
17         return;
18     }
19     pm_table[ppn].ref_counts = 0;
20 }
21
22 void
23 pmm_mark_page_occupied(ptr_t ppn, pp_attr_t attr)
24 {
25     pm_table[ppn] =
26       (struct pp_struct){ .ref_counts = 1, .attr = attr };
27 }
28
29 void
30 pmm_mark_chunk_free(ptr_t start_ppn, size_t page_count)
31 {
32     for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
33         if ((pm_table[i].attr & PP_FGLOCKED)) {
34             continue;
35         }
36         pm_table[i].ref_counts = 0;
37     }
38 }
39
40 void
41 pmm_mark_chunk_occupied(u32_t start_ppn,
42                         size_t page_count,
43                         pp_attr_t attr)
44 {
45     for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
46         pm_table[i] =
47           (struct pp_struct){ .ref_counts = 1, .attr = attr };
48     }
49 }
50
51 // 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
52 #define LOOKUP_START 1
53
54 volatile size_t pg_lookup_ptr;
55
56 void
57 pmm_init(ptr_t mem_upper_lim)
58 {
59     max_pg = pfn(mem_upper_lim);
60
61     pg_lookup_ptr = LOOKUP_START;
62
63     // mark all as occupied
64     for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) {
65         pm_table[i] =
66           (struct pp_struct){ .attr = 0, .ref_counts = 1 };
67     }
68 }
69
70 ptr_t
71 pmm_alloc_cpage(size_t num_pages, pp_attr_t attr)
72 {
73     size_t p1 = 0;
74     size_t p2 = 0;
75
76     while (p2 < max_pg && p2 - p1 < num_pages) {
77         (!(&pm_table[p2])->ref_counts) ? (p2++) : (p1 = ++p2);
78     }
79
80     if (p2 == max_pg && p2 - p1 < num_pages) {
81         return NULLPTR;
82     }
83
84     pmm_mark_chunk_occupied(p1, num_pages, attr);
85
86     return p1 << 12;
87 }
88
89 ptr_t
90 pmm_alloc_page(pp_attr_t attr)
91 {
92     // Next fit approach. Maximize the throughput!
93     ptr_t good_page_found = (ptr_t)NULL;
94     size_t old_pg_ptr = pg_lookup_ptr;
95     size_t upper_lim = max_pg;
96     struct pp_struct* pm;
97     while (!good_page_found && pg_lookup_ptr < upper_lim) {
98         pm = &pm_table[pg_lookup_ptr];
99
100         if (!pm->ref_counts) {
101             *pm = (struct pp_struct){ .attr = attr,
102                                       .ref_counts = 1 };
103             good_page_found = pg_lookup_ptr << 12;
104             break;
105         } else {
106             pg_lookup_ptr++;
107
108             // We've searched the interval [old_pg_ptr, max_pg) but failed
109             //   may be chances in [1, old_pg_ptr) ?
110             // Let's find out!
111             if (pg_lookup_ptr >= upper_lim && old_pg_ptr != LOOKUP_START) {
112                 upper_lim = old_pg_ptr;
113                 pg_lookup_ptr = LOOKUP_START;
114                 old_pg_ptr = LOOKUP_START;
115             }
116         }
117     }
118     return good_page_found;
119 }
120
121 int
122 pmm_free_one(ptr_t page, pp_attr_t attr_mask)
123 {
124     pfn_t ppfn = pfn(page);
125     struct pp_struct* pm = &pm_table[ppfn];
126
127     assert(ppfn < max_pg && pm->ref_counts);
128     if (pm->attr && !(pm->attr & attr_mask)) {
129         return 0;
130     }
131
132     pm->ref_counts--;
133     return 1;
134 }
135
136 int
137 pmm_ref_page(ptr_t page)
138 {
139     u32_t ppn = pfn(page);
140
141     if (ppn >= PM_BMP_MAX_SIZE) {
142         return 0;
143     }
144
145     struct pp_struct* pm = &pm_table[ppn];
146     assert(ppn < max_pg && pm->ref_counts);
147
148     pm->ref_counts++;
149     return 1;
150 }
151
152 void
153 pmm_set_attr(ptr_t page, pp_attr_t attr)
154 {
155     struct pp_struct* pp = &pm_table[pfn(page)];
156     
157     if (pp->ref_counts) {
158         pp->attr = attr;
159     }
160 }
161
162 struct pp_struct*
163 pmm_query(ptr_t pa)
164 {
165     u32_t ppn = pa >> 12;
166
167     if (ppn >= PM_BMP_MAX_SIZE) {
168         return NULL;
169     }
170
171     return &pm_table[ppn];
172 }