Skip to content

Commit 2476d94

Browse files
committed
pmm: properly detect first available memory region
For the first available usable region we need a space of at least EARLY_VIRT_MEM MB, which is not below first MB. Since some UEFI firmware allocates more than one usable region below the first MB with size of 4096 bytes, it is better to dynamically scan all usable regions and select the first one matching above criteria. Signed-off-by: Pawel Wieczorkiewicz <[email protected]>
1 parent 810ad44 commit 2476d94

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

mm/pmm.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
#include <mm/regions.h>
3131
#include <mm/vmm.h>
3232

33-
#define PMM_FIRST_AVAIL_REGION 1
34-
3533
size_t total_phys_memory;
3634

3735
static list_head_t frames;
@@ -246,7 +244,27 @@ static inline unsigned int find_max_avail_order(size_t size) {
246244
return PAGE_ORDER_4K;
247245
}
248246

249-
static size_t process_memory_range(unsigned index) {
247+
static unsigned find_first_avail_region(void) {
248+
addr_range_t range;
249+
250+
for (unsigned int i = 0; i < regions_num; i++) {
251+
if (get_avail_memory_range(i, &range) < 0)
252+
continue;
253+
254+
if (_paddr(range.start) < _paddr(MB(1)))
255+
continue;
256+
257+
if (_paddr(range.end) - _paddr(range.start) < MB(EARLY_VIRT_MEM))
258+
continue;
259+
260+
return i;
261+
}
262+
263+
panic("PMM: Cannot obtain first available physical memory address range\n");
264+
UNREACHABLE();
265+
}
266+
267+
static size_t process_memory_range(unsigned index, unsigned first_avail_region) {
250268
paddr_t start, end, cur;
251269
unsigned int max_order;
252270
addr_range_t range;
@@ -267,7 +285,7 @@ static size_t process_memory_range(unsigned index) {
267285

268286
/* Add initial 4K frames and align to 2M. */
269287
while ((cur < MB(EARLY_VIRT_MEM) || cur % PAGE_SIZE_2M) && cur + PAGE_SIZE <= end) {
270-
if (index <= PMM_FIRST_AVAIL_REGION)
288+
if (index <= first_avail_region)
271289
add_early_frame(paddr_to_mfn(cur), PAGE_ORDER_4K);
272290
else
273291
add_frame(paddr_to_mfn(cur), PAGE_ORDER_4K);
@@ -320,11 +338,11 @@ void reclaim_frame(mfn_t mfn, unsigned int order) {
320338
add_frame(mfn, order);
321339
}
322340

323-
static inline void check_early_frames(void) {
341+
static inline void check_early_frames(unsigned first_avail_region) {
324342
unsigned early_frames_cnt;
325343
addr_range_t range;
326344

327-
if (get_avail_memory_range(PMM_FIRST_AVAIL_REGION, &range) < 0)
345+
if (get_avail_memory_range(first_avail_region, &range) < 0)
328346
panic("PMM: Cannot obtain first available physical memory address range\n");
329347

330348
early_frames_cnt =
@@ -336,6 +354,8 @@ static inline void check_early_frames(void) {
336354
}
337355

338356
void init_pmm(void) {
357+
unsigned first_region_index;
358+
339359
printk("Initialize Physical Memory Manager\n");
340360

341361
BUILD_BUG_ON(sizeof(frames_array_t) > PAGE_SIZE);
@@ -348,13 +368,15 @@ void init_pmm(void) {
348368
list_init(&busy_frames[order]);
349369
}
350370

371+
first_region_index = find_first_avail_region();
372+
351373
/* Skip low memory range */
352-
for (unsigned int i = PMM_FIRST_AVAIL_REGION; i < regions_num; i++)
353-
total_phys_memory += process_memory_range(i);
374+
for (unsigned int i = first_region_index; i < regions_num; i++)
375+
total_phys_memory += process_memory_range(i, first_region_index);
354376

355377
display_frames_count();
356378

357-
check_early_frames();
379+
check_early_frames(first_region_index);
358380

359381
if (opt_debug)
360382
display_frames();

0 commit comments

Comments
 (0)