regression: elf loading
[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
8 static uintptr_t max_pg;
9
10 void
11 pmm_mark_page_free(uintptr_t ppn)
12 {
13     pm_table[ppn].ref_counts = 0;
14 }
15
16 void
17 pmm_mark_page_occupied(pid_t owner, uintptr_t ppn, pp_attr_t attr)
18 {
19     pm_table[ppn] =
20       (struct pp_struct){ .owner = owner, .ref_counts = 1, .attr = attr };
21 }
22
23 void
24 pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count)
25 {
26     for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
27         pm_table[i].ref_counts = 0;
28     }
29 }
30
31 void
32 pmm_mark_chunk_occupied(pid_t owner,
33                         u32_t start_ppn,
34                         size_t page_count,
35                         pp_attr_t attr)
36 {
37     for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
38         pm_table[i] =
39           (struct pp_struct){ .owner = owner, .ref_counts = 1, .attr = attr };
40     }
41 }
42
43 // 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
44 #define LOOKUP_START 1
45
46 volatile size_t pg_lookup_ptr;
47
48 void
49 pmm_init(uintptr_t mem_upper_lim)
50 {
51     max_pg = (PG_ALIGN(mem_upper_lim) >> 12);
52
53     pg_lookup_ptr = LOOKUP_START;
54
55     // mark all as occupied
56     for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) {
57         pm_table[i] =
58           (struct pp_struct){ .owner = 0, .attr = 0, .ref_counts = 1 };
59     }
60 }
61
62 void*
63 pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr)
64 {
65     size_t p1 = 0;
66     size_t p2 = 0;
67
68     while (p2 < max_pg && p2 - p1 < num_pages) {
69         (!(&pm_table[p2])->ref_counts) ? (p2++) : (p1 = ++p2);
70     }
71
72     if (p2 == max_pg && p2 - p1 < num_pages) {
73         return NULL;
74     }
75
76     pmm_mark_chunk_occupied(owner, p1, num_pages, attr);
77
78     return p1 << 12;
79 }
80
81 void*
82 pmm_alloc_page(pid_t owner, pp_attr_t attr)
83 {
84     // Next fit approach. Maximize the throughput!
85     uintptr_t good_page_found = (uintptr_t)NULL;
86     size_t old_pg_ptr = pg_lookup_ptr;
87     size_t upper_lim = max_pg;
88     struct pp_struct* pm;
89     while (!good_page_found && pg_lookup_ptr < upper_lim) {
90         pm = &pm_table[pg_lookup_ptr];
91
92         if (!pm->ref_counts) {
93             *pm = (struct pp_struct){ .attr = attr,
94                                       .owner = owner,
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     if (!good_page_found) {
112         __current->k_status = LXOUTOFMEM;
113     }
114     return (void*)good_page_found;
115 }
116
117 int
118 pmm_free_page(pid_t owner, void* page)
119 {
120     struct pp_struct* pm = &pm_table[(intptr_t)page >> 12];
121
122     // Is this a MMIO mapping or double free?
123     if (((intptr_t)page >> 12) >= max_pg || !(pm->ref_counts)) {
124         return 0;
125     }
126
127     // 如果是锁定页,则不作处理
128     if ((pm->attr & PP_FGLOCKED)) {
129         return 0;
130     }
131
132     // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放;
133     // 2) 内核可释放所有页。
134     pm->ref_counts--;
135     return 1;
136 }
137
138 int
139 pmm_ref_page(pid_t owner, void* page)
140 {
141     (void*)owner; // TODO: do smth with owner
142
143     u32_t ppn = (uintptr_t)page >> 12;
144
145     if (ppn >= PM_BMP_MAX_SIZE) {
146         return 0;
147     }
148
149     struct pp_struct* pm = &pm_table[ppn];
150     if (ppn >= max_pg || !pm->ref_counts) {
151         return 0;
152     }
153
154     pm->ref_counts++;
155     return 1;
156 }
157
158 struct pp_struct*
159 pmm_query(void* pa)
160 {
161     u32_t ppn = (uintptr_t)pa >> 12;
162
163     if (ppn >= PM_BMP_MAX_SIZE) {
164         return NULL;
165     }
166
167     return &pm_table[ppn];
168 }