pmm.c

Commit: 63d7b80c Author: jokerz Raw Copy
1
/* ============================================================================
2
 * Pactor64 — Bitmap-based Physical Memory Manager (x86-64)
3
 * Parses multiboot2 memory map, 4KB page granularity
4
 * ============================================================================ */
5
#include "../include/pactor64.h"
6
7
#define PAGE_SIZE    4096
8
#define MAX_REGIONS  32
9
10
/* Saved available regions from multiboot2 memory map */
11
typedef struct {
12
    uint64_t base;
13
    uint64_t length;
14
} mem_region_t;
15
16
/* === Bitmap === */
17
static uint8_t *pmm_bitmap   = NULL;
18
static volatile uint64_t total_pages  = 0;
19
static volatile uint64_t used_pages   = 0;
20
static uint64_t bitmap_size  = 0;
21
22
/* === Initialize PMM from multiboot2 memory map === */
23
void pmm_init(uint64_t mb2_info) {
24
    uint32_t mb2_size = *(uint32_t *)mb2_info;
25
    uint64_t highest_addr = 0;
26
27
    /*
28
     * We must extract ALL info from the multiboot2 structure FIRST,
29
     * because placing the bitmap after kernel_end may overwrite it.
30
     */
31
    mem_region_t regions[MAX_REGIONS];
32
    int num_regions = 0;
33
34
    /* Walk multiboot2 tags */
35
    uint64_t off = 8;
36
    while (off + 8 <= mb2_size) {
37
        uint32_t ttype = *(uint32_t *)(mb2_info + off);
38
        uint32_t tsize = *(uint32_t *)(mb2_info + off + 4);
39
        if (ttype == 0 || tsize < 8) break;
40
41
        if (ttype == 6) {
42
            /* Memory map tag */
43
            uint32_t entry_size = *(uint32_t *)(mb2_info + off + 8);
44
            uint8_t *entries = (uint8_t *)(mb2_info + off + 16);
45
            uint32_t entries_bytes = tsize - 16;
46
            int n = entries_bytes / entry_size;
47
48
            for (int i = 0; i < n && num_regions < MAX_REGIONS; i++) {
49
                uint64_t base = *(uint64_t *)(entries + i * entry_size);
50
                uint64_t len  = *(uint64_t *)(entries + i * entry_size + 8);
51
                uint32_t type = *(uint32_t *)(entries + i * entry_size + 16);
52
53
                if (type == 1 && len >= PAGE_SIZE) {
54
                    regions[num_regions].base   = base;
55
                    regions[num_regions].length = len;
56
                    num_regions++;
57
58
                    uint64_t top = base + len;
59
                    if (top > highest_addr) highest_addr = top;
60
                }
61
            }
62
        }
63
64
        off += tsize;
65
        off = (off + 7) & ~7ULL;
66
    }
67
68
    if (highest_addr == 0) highest_addr = 64 * 1024 * 1024;
69
    total_pages = highest_addr / PAGE_SIZE;
70
71
    /* Place bitmap right after the kernel (safe: mb2 data already parsed) */
72
    pmm_bitmap = (uint8_t *)kernel_end;
73
    bitmap_size = (total_pages + 7) / 8;
74
75
    /* Mark everything as used */
76
    kmemset(pmm_bitmap, 0xFF, bitmap_size);
77
    used_pages = total_pages;
78
79
    /* Free available regions using saved data */
80
    for (int r = 0; r < num_regions; r++) {
81
        uint64_t pg_start = (regions[r].base + PAGE_SIZE - 1) / PAGE_SIZE;
82
        uint64_t pg_end   = (regions[r].base + regions[r].length) / PAGE_SIZE;
83
        for (uint64_t pg = pg_start; pg < pg_end && pg < total_pages; pg++) {
84
            pmm_bitmap[pg / 8] &= ~(1 << (pg % 8));
85
            used_pages--;
86
        }
87
    }
88
89
    /* Re-mark kernel + bitmap region as used */
90
    uint64_t reserved_pages = ((uint64_t)pmm_bitmap + bitmap_size + PAGE_SIZE - 1) / PAGE_SIZE;
91
    for (uint64_t pg = 0; pg < reserved_pages && pg < total_pages; pg++) {
92
        if (!((pmm_bitmap[pg / 8] >> (pg % 8)) & 1)) {
93
            pmm_bitmap[pg / 8] |= (1 << (pg % 8));
94
            used_pages++;
95
        }
96
    }
97
98
    kprintf("  [OK] PMM: %d total, %d free (%d MB)\n",
99
            total_pages, total_pages - used_pages,
100
            (total_pages - used_pages) * 4 / 1024);
101
}
102
103
void *pmm_alloc_page(void) {
104
    for (uint64_t pg = 0; pg < total_pages; pg++) {
105
        if (!((pmm_bitmap[pg / 8] >> (pg % 8)) & 1)) {
106
            pmm_bitmap[pg / 8] |= (1 << (pg % 8));
107
            used_pages++;
108
            return (void *)(pg * PAGE_SIZE);
109
        }
110
    }
111
    return NULL;
112
}
113
114
void pmm_free_page(void *page) {
115
    uint64_t pg = (uint64_t)page / PAGE_SIZE;
116
    if (pg < total_pages && ((pmm_bitmap[pg / 8] >> (pg % 8)) & 1)) {
117
        pmm_bitmap[pg / 8] &= ~(1 << (pg % 8));
118
        used_pages--;
119
    }
120
}
121
122
uint64_t pmm_get_free_pages(void) {
123
    return total_pages - used_pages;
124
}
125
126
uint64_t pmm_get_total_pages(void) {
127
    return total_pages;
128
}
129