~cypheon/xos

567db6047e7a21cac97f48d376819045b6e9d458 — Johann Rudloff 6 years ago 34e5dbf master
Implement scanning and allocation of physical memory.
M Makefile => Makefile +1 -1
@@ 1,6 1,6 @@
INCLUDE = include

KERNEL = kernel.o ide.o console.o ext2.o blockdev.o kmem.o paging.o atpic.o proc.o scheduler.o
KERNEL = kernel.o ide.o console.o ext2.o blockdev.o kmem.o paging.o atpic.o proc.o scheduler.o bitmap.o
HEADERS = $(shell find include/ -type f)

CC = i686-elf-gcc

A bitmap.c => bitmap.c +75 -0
@@ 0,0 1,75 @@
#include <sys/bitmap.h>
#include <sys/types.h>
#include <stdlib.h>

struct bitmap *
bitmap_create(void *mem, uint32_t available, size_t bitmap_size) {
  /* check, if it fits */
  if (available < bitmap_required_size(bitmap_size)) {
    return NULL;
  }

  struct bitmap *bm = (struct bitmap *)mem;
  bm->size = bitmap_size;
  bm->first_clear = 0;
  bm->area = (uint32_t *)(mem + sizeof(struct bitmap *));

  memset(bm->area, 0, ((bitmap_size + 31) / 32) * 4);

  return NULL;
}

void
bitmap_set(struct bitmap *bm, uint32_t index) {
  uint32_t area_index = index / 32;
  uint32_t mask = 1 << (index % 32);
  bm->area[area_index] |= mask;
}

void
bitmap_clear(struct bitmap *bm, uint32_t index) {
  uint32_t area_index = index / 32;
  uint32_t mask = ~(1 << (index % 32));
  bm->area[area_index] &= mask;
  if (area_index < bm->first_clear) {
    bm->first_clear = area_index;
  }
}

int
bitmap_get(struct bitmap *bm, uint32_t index) {
  uint32_t area_index = index / 32;
  uint32_t mask = 1 << (index % 32);
  return (bm->area[area_index] & mask);
}

uint32_t
bitmap_find_clear(struct bitmap *bm) {
  for(uint32_t area_index = bm->first_clear; area_index < bm->size; ++area_index) {
    if (bm->area[area_index] != 0xffffffff) {
      area_index *= 32;
      uint32_t value = bm->area[area_index];
      while (value & 1) {
        area_index++;
        value >>= 1;
      }
      return area_index;
    }
  }

  return 0;
}

void
bitmap_range_update(struct bitmap *bm, uint32_t start, uint32_t count, int value) {
  // TODO: this is a very naive implementation, replace with a real one
  if (value) {
    for (uint32_t index=start; index<start+count; ++index) {
      bitmap_set(bm, index);
    }
  } else {
    for (uint32_t index=start; index<start+count; ++index) {
      bitmap_clear(bm, index);
    }
  }
}

M include/stdlib.h => include/stdlib.h +9 -0
@@ 29,4 29,13 @@ static inline void memcpy(void *dst, const void *src, uint32_t size) {
  }
}

static inline void *memset(void *b, int c, size_t len) {
  uint8_t x = (uint8_t)c;
  uint8_t *p = b, *end=p-len;
  while(p<end) {
    *p++ = x;
  }
  return b;
}

#endif /* _STDLIB_H_ */

A include/sys/bitmap.h => include/sys/bitmap.h +29 -0
@@ 0,0 1,29 @@
#ifndef _BITMAP_H_
#define _BITMAP_H_

#include <sys/types.h>

struct bitmap {
  /* number of bits */
  size_t size;
  /* area_index, where the first clear bit might be found */
  uint32_t first_clear;
  /* data */
  uint32_t *area;
};

struct bitmap *bitmap_create(void *mem, uint32_t available, size_t bitmap_size);

int bitmap_get(struct bitmap *bm, uint32_t index);
void bitmap_set(struct bitmap *bm, uint32_t index);
void bitmap_clear(struct bitmap *bm, uint32_t index);
void bitmap_update(struct bitmap *bm, uint32_t index, int value);
void bitmap_range_update(struct bitmap *bm, uint32_t start, uint32_t count, int value);
uint32_t bitmap_find_clear(struct bitmap *bm);

static inline uint32_t
bitmap_required_size(size_t bitmap_size) {
  return (sizeof(struct bitmap) + ((bitmap_size + 31) / 32) * 4);
}

#endif /* _BITMAP_H_ */

M include/sys/kernel.h => include/sys/kernel.h +0 -2
@@ 3,8 3,6 @@

#include <sys/console.h>

#define NULL ((void *)0)

void panic(const char *msg);

#endif /* _KERNEL_H_ */

M include/sys/memory.h => include/sys/memory.h +3 -9
@@ 11,15 11,9 @@ void *kmalloc(size_t size);
void *kmalloc_align(size_t alignment, size_t size);
void kfree(void *p);

static inline void *memset(void *b, int c, size_t len) {
  uint8_t x = (uint8_t)c;
  uint8_t *p = b, *end=p-len;
  while(p<end) {
    *p++ = x;
  }
  return b;
}

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

uint32_t phys_aquire_page(void);
void phys_release_page(uint32_t page);

#endif /* _MEMORY_H_ */

M include/sys/types.h => include/sys/types.h +5 -0
@@ 11,4 11,9 @@ typedef int int32_t;

typedef unsigned int size_t;

#define NULL ((void *)0)

#define UINT32_MAX 0xffffffff
#define UINT32_ADD_OVERFLOW(a,b) ((a) > (UINT32_MAX - (b)))

#endif /* _TYPES_H_ */

M kmem.c => kmem.c +96 -7
@@ 1,3 1,4 @@
#include <sys/bitmap.h>
#include <sys/console.h>
#include <sys/kernel.h>
#include <sys/memory.h>


@@ 9,6 10,9 @@
#define KMEM_ARENA_START 0x200000
#define KMEM_ARENA_END 0x400000

// First non-reserved phys memory address
#define PHYS_RESERVED 0x200000

struct memory_map_entry {
  uint32_t base_low;
  uint32_t base_high;


@@ 20,6 24,9 @@ struct memory_map_entry {

struct kmem {
  void *free; // first free page
  uint32_t phys_pages_total;
  uint32_t phys_pages_available;
  struct bitmap *phys_pages;
};

struct free_info {


@@ 28,6 35,26 @@ struct free_info {

static struct kmem kmem_state;

static void *lowmem_next = 0x10000;
static const void *lowmem_max = 0x80000;
static void *
lowmem_alloc(size_t size) {
  if (lowmem_next + size >= lowmem_max) { return NULL; }
  void *p = lowmem_next;
  lowmem_next += size;
  return p;
}

static int
memory_usable(struct memory_map_entry *m) {
  return ((m->type == 1) &&
        (m->base_high == 0) &&
        (m->base_low + m->length_low > PHYS_RESERVED) &&
        (m->length_low > 0) &&
        (m->length_high == 0) &&
        !UINT32_ADD_OVERFLOW(m->base_low, m->length_low));
}

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) {


@@ 51,15 78,77 @@ void kmem_init(uint32_t memory_map_entry_count, struct memory_map_entry *entries

void
kmem_detect(uint32_t count, struct memory_map_entry *mmap) {
  khexprint("mmap count", count);
  uint32_t highest = 0;
  for (int i=0; i<count; ++i) {
    if (!memory_usable(mmap + i)) {
      khexprint("=========== SKIP 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);
      continue;
    }
    if ((mmap[i].base_low + mmap[i].length_low) > highest) {
      highest = mmap[i].base_low + mmap[i].length_low;
    }
  }
  kmem_state.phys_pages_total = highest / PAGE_SIZE;
  void *bm_mem = lowmem_alloc(bitmap_required_size(kmem_state.phys_pages_total));
  struct bitmap *bm = kmem_state.phys_pages = bitmap_create(bm_mem,
      bitmap_required_size(kmem_state.phys_pages_total),
      kmem_state.phys_pages_total);

  // initally, mark all memory as unusable
  bitmap_range_update(bm, 0, kmem_state.phys_pages_total, 1);

  uint32_t available_count = 0;
  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);
    if (!memory_usable(mmap + i)) {
      continue;
    }
    uint32_t start = mmap[i].base_low;
    uint32_t end = mmap[i].base_low + mmap[i].length_low;
    if (end < PHYS_RESERVED) {
      continue;
    }
    if (start < PHYS_RESERVED) {
      start = PHYS_RESERVED;
    }

    khexprint("=========== USE 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);
    khexprint("  actual_start", start);
    khexprint("  actual_end", end);

    // first completely usable page
    uint32_t first_page = (start + PAGE_SIZE - 1) / PAGE_SIZE;

    // first page that is not completely usable
    uint32_t last_page = end / PAGE_SIZE;

    // mark memory as unused(available)
    bitmap_range_update(bm, first_page, last_page, 0);
    available_count += (last_page - first_page);
  }
  khexprint("============ Memory detection complete\n  total memory",
      available_count*PAGE_SIZE);
}

uint32_t
phys_aquire_page(void) {
  uint32_t page = bitmap_find_clear(kmem_state.phys_pages);
  bitmap_set(kmem_state.phys_pages, page);
  return page;
}

void
phys_release_page(uint32_t page) {
  bitmap_clear(kmem_state.phys_pages, page);
}

void *kmem_alloc_pages(size_t pages) {