summaryrefslogtreecommitdiff
path: root/kc/core/memory/page_early.c
blob: 989f82a98998061fe3baa02cb9fdf2c5c2a88e83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "page_early.h"
#include "panic.h"

#include <libc/stdio.h>

static struct page_early_state
{
    struct memory_range *first;
    struct memory_range *current;
    struct memory_range *last;
}
early_state;

void page_early_init(void)
{
    printf("initializing early page frame allocator\n");
    struct kc_boot_data *boot_data = get_boot_data();

    early_state.first = &boot_data->memory.entries[0];
    early_state.last = &boot_data->memory.entries[boot_data->memory.count];
    early_state.current = early_state.first;

    /*printf("memory ranges\n");

    struct memory_range *current = early_state.first;

    do
    {
        printf("base %#0.16lx size %#0.16lx type %d\n", current->base, current->size, current->type);
        current++;
    }
    while (current != early_state.last);
	*/
}

void page_early_final(void)
{
    if (early_state.first)
    {
        printf("finalizing early page allocator\n");
        for (struct memory_range *current = early_state.first; 
                current < early_state.last;
                current++)
        {
            while (current->type != RESERVED_MEMORY && current->size >= page_size(1))
            {
                current->size -= page_size(1);

                enum memory_range_type type = current->type;
                kc_phys_addr page = current->base + current->size;
                // all pages are gonna be set allocated first
                // to initialize the tracking structure at the other side
                // and make setting the page free as simple as 
                // calling page_free();
                page_set_allocated(page);

                switch (type)
                {
                    case SYSTEM_MEMORY:
                        page_set_present(page);
                        break;
                    case AVAILABLE_MEMORY:
                        page_set_present(page);
                        page_free(page);
                        break;
                    case FIRMWARE_MEMORY:
                    case MMIO_MEMORY:
                        break;
                    default:
                        break;
                }
            }
        }

        early_state = (struct page_early_state){NULL, NULL, NULL};
    }
}

kc_phys_addr page_early_alloc(enum page_alloc_flags type)
{
    // TODO: support low/conv/high allocations in early_alloc.
    // currently we only have conventional allocations enforced
    // by the conditions of the scanning loop
    (void)type;

    while(early_state.current)
    {
        if ((early_state.current->type == AVAILABLE_MEMORY) &&
                (early_state.current->base > 0x10000) &&
            (early_state.current->size > page_size(1)))
        {
            early_state.current->size -= page_size(1);
            return early_state.current->base + early_state.current->size;
        }

        if (early_state.current == early_state.last)
        {
            early_state.current = NULL;
            break;
        }
        early_state.current++;
    }

    printf("error: early allocator has run out of memory\n");
    PANIC(OUT_OF_MEMORY);
}