~cypheon/xos

ref: b2547584ec8bf9723cd5e49697130506b5a65ca6 xos/kmem.c -rw-r--r-- 3.2 KiB
b2547584 — Johann Rudloff Minor improvements, dont hardcode memory map base address. 7 years ago
                                                                                
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <sys/console.h>
#include <sys/kernel.h>
#include <sys/memory.h>
#include <sys/paging.h>

#define DEBUG
#include <debug.h>

#define KMEM_ARENA_START 0x200000
#define KMEM_ARENA_END 0x400000

struct memory_map_entry {
  uint32_t base_low;
  uint32_t base_high;
  uint32_t length_low;
  uint32_t length_high;
  uint16_t type;
  uint16_t pad;
} __attribute__ ((__packed__));

struct kmem {
  void *free; // first free page
};

struct free_info {
  struct free_info *next; // start of next free page
};

static struct kmem kmem_state;

void kmem_detect(uint32_t count, struct memory_map_entry *mmap);

void kmem_init(uint32_t memory_map_entry_count, struct memory_map_entry *entries) {
  kmem_detect(memory_map_entry_count, entries);

  // begin with the last page
  void *page = (void *)(KMEM_ARENA_END - PAGE_SIZE);

  void *previous = (void *)0;
  struct free_info *free;

  while (page >= (void *)KMEM_ARENA_START) {
    free = (struct free_info *)page;
    free->next = previous;
    previous = page;
    page -= PAGE_SIZE;
  }

  kmem_state.free = previous;
}

void
kmem_detect(uint32_t count, struct memory_map_entry *mmap) {
  khexprint("mmap count", count);
  for (int i=0; i<count; ++i) {
    khexprint("=========== mmap entry", i);
    khexprint("base_low", mmap[i].base_low);
    khexprint("base_high", mmap[i].base_high);
    khexprint("length_low", mmap[i].length_low);
    khexprint("length_high", mmap[i].length_high);
    khexprint("type", mmap[i].type);
  }
}

void *kmem_alloc_pages(size_t pages) {
  if (pages != 1) {
    panic("can only alloc one page at a time");
  }

  void *p = kmem_state.free;
  struct free_info *fi = (struct free_info *)kmem_state.free;
  kmem_state.free = fi->next;

  return p;
}

void kmem_free_pages(void *start, size_t pages) {
  if (pages != 1) {
    panic("can only free one page at a time");
  }

  struct free_info *fi = (struct free_info *)start;
  if (start < kmem_state.free) {
    // page will be the first free page
    fi->next = kmem_state.free;
    kmem_state.free = start;
  } else {
    // find previous page
    struct free_info *free = (struct free_info *)kmem_state.free;
    while (free->next && (void *)free->next < start) {
      free = free->next;
    }
    fi->next = free->next;
    free->next = fi;
  }
}

void *kmalloc(size_t size) {
  size_t pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
  return kmem_alloc_pages(pages);
  /**(size_t *)km_state.next = size;*/
  /*km_state.next += sizeof(size_t);*/
  /*void *p = km_state.next;*/
  /*km_state.next += size;*/
  /*return p;*/
}

void *kmalloc_align(size_t alignment, size_t size) {
  size_t pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
  return kmem_alloc_pages(pages);
  /*size_t align_offset = (((size_t)km_state.next) + sizeof(size_t)) % alignment;*/
  /*if (align_offset == 0) {*/
    /*return kmalloc(size);*/
  /*} else {*/
    /*size_t padding_size = alignment - align_offset;*/
    /*if (padding_size <= sizeof(size_t)) {*/
      /*padding_size += alignment;*/
    /*}*/
    /*void *padding = kmalloc(padding_size - sizeof(size_t));*/
    /*void *p = kmalloc(size);*/
    /*kfree(padding);*/
    /*return p;*/
  /*}*/
}

void kfree(void *p) {
  if (p == NULL) return;

  // TODO: implement
  kmem_free_pages(p, 1);
}