:: limine / common / lib / elsewhere.c 3.2 KB raw

1
#include <stdint.h>
2
#include <stddef.h>
3
#include <stdbool.h>
4
#include <lib/elsewhere.h>
5
#include <lib/misc.h>
6
#include <mm/pmm.h>
7
8
static bool elsewhere_overlap_check(uint64_t base1, uint64_t top1,
9
                              uint64_t base2, uint64_t top2) {
10
    return (base1 < top2 && base2 < top1);
11
}
12
13
bool elsewhere_append(
14
        bool flexible_target,
15
        struct elsewhere_range *ranges, uint64_t *ranges_count,
16
        uint64_t ranges_max,
17
        void *elsewhere, uint64_t *target, size_t t_length) {
18
    // original target of -1 means "allocate after top of all ranges"
19
    // flexible target is ignored
20
    flexible_target = true;
21
    if (*target == (uint64_t)-1) {
22
        uint64_t top = 0;
23
24
        for (size_t i = 0; i < *ranges_count; i++) {
25
            uint64_t r_top = CHECKED_ADD(ranges[i].target, ranges[i].length, continue);
26
27
            if (top < r_top) {
28
                top = r_top;
29
            }
30
        }
31
32
        *target = ALIGN_UP(top, 4096, return false);
33
    }
34
35
    uint64_t max_retries = 0x10000;
36
37
retry:
38
    if (max_retries-- == 0) {
39
        return false;
40
    }
41
42
    for (size_t i = 0; i < *ranges_count; i++) {
43
        uint64_t t_top = CHECKED_ADD(*target, t_length, return false);
44
45
        // Ensure allocation stays within 32-bit address space.
46
        if (t_top > 0x100000000) {
47
            return false;
48
        }
49
50
        // Does it overlap with other elsewhere ranges targets?
51
        {
52
            uint64_t base = ranges[i].target;
53
            uint64_t length = ranges[i].length;
54
            uint64_t top = CHECKED_ADD(base, length, continue);
55
56
            if (elsewhere_overlap_check(base, top, *target, t_top)) {
57
                if (!flexible_target) {
58
                    return false;
59
                }
60
                *target = ALIGN_UP(top, 4096, return false);
61
                goto retry;
62
            }
63
        }
64
65
        // Does it overlap with other elsewhere ranges sources?
66
        {
67
            uint64_t base = ranges[i].elsewhere;
68
            uint64_t length = ranges[i].length;
69
            uint64_t top = CHECKED_ADD(base, length, continue);
70
71
            if (elsewhere_overlap_check(base, top, *target, t_top)) {
72
                if (!flexible_target) {
73
                    return false;
74
                }
75
                *target = ALIGN_UP(top, 4096, return false);
76
                goto retry;
77
            }
78
        }
79
80
        // Make sure it is memory that actually exists.
81
        if (!memmap_alloc_range(*target, t_length, MEMMAP_BOOTLOADER_RECLAIMABLE,
82
                                MEMMAP_USABLE, false, true, false)) {
83
            if (!memmap_alloc_range(*target, t_length, MEMMAP_BOOTLOADER_RECLAIMABLE,
84
                                    MEMMAP_BOOTLOADER_RECLAIMABLE, false, true, false)) {
85
                if (!flexible_target) {
86
                    return false;
87
                }
88
                *target += 0x1000;
89
                goto retry;
90
            }
91
        }
92
    }
93
94
    // Add the elsewhere range
95
    if (*ranges_count >= ranges_max) {
96
        panic(false, "elsewhere: ranges array overflow");
97
    }
98
    ranges[*ranges_count].elsewhere = (uintptr_t)elsewhere;
99
    ranges[*ranges_count].target = *target;
100
    ranges[*ranges_count].length = t_length;
101
    *ranges_count += 1;
102
103
    return true;
104
}
tab: 248 wrap: offon