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