Verified Commit a44a6f29 authored by Allie Sargente's avatar Allie Sargente 😑

Higher half, mostly

Also so ADT stuff
Signed-off-by: Allie Sargente's avatarAllison Sargente <[email protected]>
parent 3b195499
No preview for this file type
No preview for this file type
No preview for this file type
/*
* (c) 2019 Apollo Developers
* For terms, see LICENSE
* bitmap.c - ADT for bitmap storage
*/
#include <adt/bitmap.h>
#include <sys/hal.h>
#include <assert.h>
#include <string.h>
// Return index of lsb that is set in byte. byte==0 undefined.
static int lsb_set(uint8_t byte)
{
int i = 0;
while ((byte & 1) == 0) {
i++;
byte >>= 1;
}
return i;
}
void bitmap_init(bitmap_t *xb, uint8_t *storage, int64_t max_extent)
{
xb->max_extent = max_extent;
xb->data = storage;
memset(xb->data, 0, max_extent / 8 + 1);
}
void bitmap_set(bitmap_t *xb, unsigned idx)
{
xb->data[idx/8] |= (1 << (idx % 8));
assert(bitmap_isset(xb, idx));
}
void bitmap_clear(bitmap_t *xb, unsigned idx)
{
xb->data[idx/8] &= ~(1 << (idx % 8));
}
int bitmap_isset(bitmap_t *xb, unsigned idx)
{
return (xb->data[idx/8] & (1 << (idx % 8))) ? 1 : 0;
}
int bitmap_isclear(bitmap_t *xb, unsigned idx)
{
return !bitmap_isset(xb, idx);
}
int64_t bitmap_first_set(bitmap_t *xb)
{
uint64_t i;
int64_t idx;
for (i = 0; i < (xb->max_extent >> 3) + 1ULL; i++) {
if (xb->data[i] == 0) {
continue;
}
idx = i * 8 + lsb_set(xb->data[i]);
return (idx > xb->max_extent) ? -1 : idx;
}
return -1;
}
/*
* (c) 2019 Apollo Developers
* For terms, see LICSENSE
* buddy allocator
* Allocation: log(n) Free: log(n)
*/
#include <sys/hal.h>
#include <assert.h>
#include <math.h>
#include <adt/buddy.h>
#define BUDDY(x) (x ^ 1)
#define INC_ORDER(x) (x << 1)
#define DEC_ORDER(x) (x >> 1)
size_t buddy_calc_overhead(range_t r)
{
size_t accum = 0;
unsigned i;
for (i = MIN_BUDDY_SZ_LOG2; i <= MAX_BUDDY_SZ_LOG2; i++) {
accum += (r.extent >> i) / 8 + 1;
}
return accum;
}
int buddy_init(buddy_t *bd, uint8_t *overhead_store, range_t r, int start_freed)
{
unsigned i, nbits;
bd->start = r.start;
bd->size = r.extent;
for(i = 0; i < NUM_BUDDY_BUCKETS; i++) {
nbits = bd->size >> (MIN_BUDDY_SZ_LOG2 + i);
bitmap_init(&bd->orders[i], overhead_store, nbits);
overhead_store += nbits / 8 + 1;
}
if (start_freed != 0) {
buddy_free_range(bd, r);
}
return 0;
}
uint64_t buddy_alloc(buddy_t *bd, unsigned sz)
{
unsigned log_sz = log2_roundup(sz);
if(log_sz > MAX_BUDDY_SZ_LOG2) {
panic("buddy_alloc had request that was too large to handle");
}
unsigned orig_log_sz = log_sz;
// Search for a free block -- we may need to increase the size of the block
// to find a free one
int64_t idx;
while (log_sz <= MAX_BUDDY_SZ_LOG2) {
idx = bitmap_first_set(&bd->orders[log_sz - MIN_BUDDY_SZ_LOG2]);
if(idx != -1) {
// we found a block
break;
}
log_sz++;
}
if (idx == -1) {
// No free blocks
return ~0ULL;
}
// Split blocks to get a block of minimum size
for(; log_sz != orig_log_sz; log_sz--) {
int order_idx = log_sz - MIN_BUDDY_SZ_LOG2;
// splitting a block, so deallocate it first.
bitmap_clear(&bd->orders[order_idx], idx);
// Set both children as free.
idx = INC_ORDER(idx);
bitmap_set(&bd->orders[order_idx - 1], idx);
bitmap_set(&bd->orders[order_idx - 1], idx + 1);
}
int order_idx = log_sz - MIN_BUDDY_SZ_LOG2;
bitmap_clear(&bd->orders[order_idx], idx);
uint64_t addr = bd->start + ((uint64_t)idx << log_sz);
return addr;
}
static int aligned_for(uint64_t addr, uintptr_t lg2)
{
uintptr_t mask = ~( ~0ULL << lg2 );
return (addr & mask) == 0;
}
void buddy_free(buddy_t *bd, uint64_t addr, unsigned sz)
{
uint64_t offs = addr - bd->start;
unsigned log_sz = log2_roundup(sz);
unsigned idx = offs >> log_sz;
while (log_sz >= MIN_BUDDY_SZ_LOG2) {
int order_idx = log_sz - MIN_BUDDY_SZ_LOG2;
// Mark node free
bitmap_set(&bd->orders[order_idx], idx);
// Can we coalese up another level?
if (log_sz == MAX_BUDDY_SZ_LOG2) {
break;
}
if (bitmap_isset(&bd->orders[order_idx], BUDDY(idx)) == 0) {
// guess not...
break;
}
// Mark both non-free
bitmap_clear(&bd->orders[order_idx], idx);
bitmap_clear(&bd->orders[order_idx], BUDDY(idx));
// Move up an order
idx = DEC_ORDER(idx);
log_sz++;
}
}
void buddy_free_range(buddy_t *bd, range_t range)
{
unsigned i;
uint64_t old_start, start;
uintptr_t sz, min_sz;
min_sz = 1 << MIN_BUDDY_SZ_LOG2;
if (aligned_for(range.start, MIN_BUDDY_SZ_LOG2) == 0) {
if (range.extent < min_sz) {
return;
}
old_start = range.start;
range.start &= ~0ULL << MIN_BUDDY_SZ_LOG2;
range.start += min_sz;
range.extent -= range.start - old_start;
}
while (range.extent >= min_sz &&
aligned_for(range.start, MIN_BUDDY_SZ_LOG2)) {
for(i = MAX_BUDDY_SZ_LOG2; i >= MIN_BUDDY_SZ_LOG2; i--) {
sz = 1 << i;
start = range.start - bd->start;
if (sz > range.extent || aligned_for(start, i) == 0) {
continue;
}
range.extent -= sz;
range.start += sz;
buddy_free(bd, start + bd->start, sz);
break;
}
}
}
......@@ -6,6 +6,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[GLOBAL mboot]
[EXTERN higherhalf]
; Multiboot Macro Definitions
MULTIBOOT_PAGE_ALIGN equ 1<<0
......@@ -28,8 +29,37 @@ mboot:
dd MULTIBOOT_HEADER_FLAGS
dd MULTIBOOT_CHECKSUM
global _start:function _start.end-_start
_start:
mov eax, pd ; Move magic number into pd
mov dword [eax], pt + 3 ; addrs 0 - 0x400000
mov dword [eax+0xC00], pt+3 ; addrs 0xC0000000 - 0xC0400000
;; Loop through all 1024 pages in pt, set them to identity mapped
mov edx, pt ;
mov ecx, 0 ; start a loop
.loop:
mov eax, ecx ; grab loop number
shl eax, 12 ;
or eax, 3 ; Bit twiddling
mov [edx+ecx*4], eax ; pt[ecx * sizeof(entry)] -> tmp
inc ecx ;
cmp ecx, 1024 ; End condition
jnz .loop ; loop back otherwise
mov eax, pd+3 ; load page directory
mov cr3, eax ; load into cr3
mov eax, cr0 ; grab cr0
or eax, 0x80000000 ; set PG Bit
mov cr0, eax ; push cr0 back
jmp higherhalf ; start kernel proper
.end: ; end of function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Multiboot Padding
section .init.bss nobits
pd: resb 0x1000
pt: resb 0x1000
pd: resb 0x1000 ; Descriptors
pt: resb 0x1000 ; Page tabled
......@@ -15,29 +15,33 @@ KERNEL_STACK_SIZE equ 0x4000
[EXTERN bss]
[EXTERN end]
;==========================;
; Bootloader dropoff point ;
;==========================;
start:
; Set up stack
mov esp, KERNEL_STACK + KERNEL_STACK_SIZE
push eax ; Should be the multiboot magic number
push ebx ; Should be the multiboot header
;============================;
; Bootloader's dropoff point ;
; Dropped here from start ;
;============================;
section .text
global higherhalf:function higherhalf.end-higherhalf
higherhalf:
mov esp, stack ; Multiboot doesnt give us a valid stack
xor ebp, ebp ; Clear the stack frame
push ebx ; Should be multiboot header
cli ; Make sure we don't get any errornous interrupts
call arch_init ; Pass control to C
cli ;
jmp $ ; endless loop
hlt ; Deadlock Stop.
jmp $ ; In case we get an NMI
.end: ;
;;;;;;;;;;;;;;;;;;;;;;;;;
; Stack
;=======
section .bss
ALIGN 8192
KERNEL_STACK:
global stack_base
stack_base:
resb KERNEL_STACK_SIZE
stack: ; label for esp only (bottom of the stack)
section .comment
KERN_INFO:
......
ENTRY(start)
OUTPUT_ARCH("i386")
OUTPUT_FORMAT("elf32-i386")
ENTRY(_start)
SECTIONS
{
.init 0x100000 :
......@@ -11,16 +15,26 @@ SECTIONS
{
*(.init.bss)
}
/* Higher half stuff, add 3GB to all addresses below */
. += 0xC0000000;
.text ALIGN(4096) :
.text ALIGN(4096) : AT(ADDR(.text) - 0xC0000000)
{
code = .; _code = .; __code = .;
*(.text)
*(.mboot)
*(.text.unlikely .text.*_unlikely)
*(.text.exit .text.exit.*)
*(.text.startup text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
*(.gnu.warning)
}
.rodata ALIGN(4096) : AT(ADDR(.rodata) - 0xC0000000)
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
}
.data ALIGN(4096) :
.data ALIGN(4096) : AT(ADDR(.data) - 0xC0000000)
{
PROVIDE (__startup_begin = .);
*(.startup)
......@@ -28,21 +42,21 @@ SECTIONS
PROVIDE (__shutdown_begin = .);
*(.shutdown)
PROVIDE (__shutdown_end = .);
*(.data .data.* .gnu.linkonce.d)
SORT(CONSTRUCTORS)
data = .; _data = .; __data = .;
*(.data .data.* .gnu.linkonce.d)
PROVIDE(__ctors_begin = .);
*(.ctors)
PROVIDE(__ctors_end = .);
*(.rodata)
}
.bss ALIGN(4096):
.bss ALIGN(4096) : AT(ADDR(.bss) - 0xC0000000)
{
bss = .; _bss = .; __bss = .;
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
PROVIDE(__end = . - 0xC0000000);
}
PROVIDE(__end = .);
end = .; _end = .; __end = .;
/* end of kernel symbol */
_kernel_end = .;
}
#ifndef BITMAP_H
#define BITMAP_H
#include <stdint.h>
// This ADT exposes a statically sized bitmap.
typedef struct bitmap {
uint8_t *data;
int64_t max_extent;
} bitmap_t;
void bitmap_init(bitmap_t *xb, uint8_t *storage, int64_t max_extent);
// Set a bit at index idx
void bitmap_set(bitmap_t *xb, unsigned idx);
// Clear a bit at index idx
void bitmap_clear(bitmap_t *xb, unsigned idx);
// Returns nonzero if bit set at idx
int bitmap_isset(bitmap_t *xb, unsigned idx);
// Returns nonzero if bit is clear at idx
int bitmap_isclear(bitmap_t *xb, unsigned idx);
// Return the index of the first bit set, or -1 if no bits are sets
int64_t bitmap_first_set(bitmap_t *xb);
#endif
#ifndef BUDDY_H
#define BUDDY_H
#include <stdint.h>
#include <adt/bitmap.h>
#define MAX_BUDDY_SZ_LOG2 28 // 2^28 = 256MB
#define MIN_BUDDY_SZ_LOG2 12 // 2^12 = 4KB
#define NUM_BUDDY_BUCKETS (MAX_BUDDY_SZ_LOG2 - MIN_BUDDY_SZ_LOG2 + 1)
typedef struct buddy {
uint64_t start, size;
bitmap_t orders[NUM_BUDDY_BUCKETS];
} buddy_t;
size_t buddy_calc_overhead(range_t r);
int buddy_init(buddy_t *bd, uint8_t *overhead_store, range_t r, int start_freed);
uint64_t buddy_alloc(buddy_t *bd, unsigned sz);
void buddy_free_range(buddy_t *bd, range_t range);
void buddy_free(buddy_t *bd, uint64_t addr, unsigned sz);
extern buddy_t kernel_buddy;
#endif
#ifndef X86_MMAP_H
#define X86_MMAP_H
#define MMAP_KERNEL_START 0xC0000000
// At least 64MB of address space for 36-bit physical Addresses
#define MMAP_COW_REFCNTS 0xCC000000
#define MMAP_KERNEL_VMSPACE_START 0xD0000000
#define MMAP_KERNEL_VMSPACE_END 0xFE800000
#define MMAP_PMM_BITMAP 0xFE800000
#define MMAP_PMM_BITMAP_END 0xFF800000
#define MMAP_KERNEL_END 0xFF800000
#define IS_KERNEL_ADDR(x) ((void*)(x) >= (void*)MMAP_KERNEL_START)
#endif
#ifndef MATH_H
#define MATH_H
unsigned log2_roundup(unsigned n);
#endif
#ifndef MMAP_H
#define MMAP_H
// This file steps to includes for arch specific mmap's
#if defined(X64)
#include <arch/x64/mmap.h>
#elif defined(X86)
#include <arch/x86/mmap.h>
#elif defined(HOSTED)
#include <arch/hosted/mmap.h>
#endif
#endif
/*
* (c) 2019 Apollo Developers
* For terms, see LICENSE
* math.c - math helper functions
*/
#include <math.h>
unsigned log2_roundup(unsigned n)
{
// Calculate the floor of log2(n)
unsigned l2;
l2 = 31 - __builtin_clz(n); // gcc builtin, returns number of leading 0's
// in n, if x is 0, result undefined.
// TODO: I hate using builtins
if (n == 1U << l2) { // n == 2^log2(n), floor(n) = n
return l2; // no need to round up
}
// floor(n) != n, return round up
return l2 + 1;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment