~cypheon/xos

ref: 666e83dc8928b3ec9831d91515bdb4d183e7d25f xos/kmem.c -rw-r--r-- 3.2 KiB
666e83dc — Johann Rudloff Add memory map detection in bootloader. 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
132
133
134
#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 detect_mmap_info {
  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(void);

void kmem_init(void) {
  kmem_detect();

  // 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(void) {
  uint32_t mmap_count = *(uint32_t *)0x1000;
  struct detect_mmap_info *mmap = (struct detect_mmap_info *)(0x1000 + 4);
  khexprint("mmap count", mmap_count);
  khexprint("mmap size", sizeof(struct detect_mmap_info));
  for (int i=0; i<mmap_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);
}