kernel: adjust formatting
This commit is contained in:
@@ -1,17 +1,18 @@
|
||||
#include <mango/status.h>
|
||||
#include <limits.h>
|
||||
#include <mango/vm.h>
|
||||
#include <mango/machine/cpu.h>
|
||||
#include <mango/memblock.h>
|
||||
#include <mango/printk.h>
|
||||
#include <mango/machine/cpu.h>
|
||||
#include <mango/status.h>
|
||||
#include <mango/vm.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* One struct vm_pg_data per NUMA node. */
|
||||
static struct vm_pg_data *node_data = NULL;
|
||||
|
||||
kern_status_t vm_bootstrap(const struct vm_zone_descriptor *zones, size_t nr_zones)
|
||||
kern_status_t vm_bootstrap(
|
||||
const struct vm_zone_descriptor *zones,
|
||||
size_t nr_zones)
|
||||
{
|
||||
int numa_count = 1;
|
||||
|
||||
@@ -34,7 +35,7 @@ kern_status_t vm_bootstrap(const struct vm_zone_descriptor *zones, size_t nr_zon
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nr_zones; i++) {
|
||||
vm_zone_init(&node_data->pg_zones[zones[i].zd_id], &zones[i]);
|
||||
vm_zone_init(&node_data->pg_zones[zones[i].zd_id], &zones[i]);
|
||||
}
|
||||
|
||||
kmalloc_init();
|
||||
|
||||
190
vm/memblock.c
190
vm/memblock.c
@@ -19,27 +19,29 @@
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <mango/types.h>
|
||||
#include <mango/libc/string.h>
|
||||
#include <mango/memblock.h>
|
||||
#include <mango/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define ITER(a, b) ((uint64_t)(a) | ((uint64_t)(b) << 32))
|
||||
#define ITER_END ULLONG_MAX
|
||||
#define ITER_END ULLONG_MAX
|
||||
#define IDX_A(idx) ((idx) & 0xFFFFFFFF)
|
||||
#define IDX_B(idx) (((idx) >> 32) & 0xFFFFFFFF)
|
||||
|
||||
/* the maximum possible value for a pointer type.
|
||||
Note that any pointers returned by the memblock API will still
|
||||
be bounded by the defined memory regions, and not by this constant. */
|
||||
#define ADDR_MAX (~(uintptr_t)0)
|
||||
#define ADDR_MAX (~(uintptr_t)0)
|
||||
|
||||
static struct memblock_region init_memory_regions[MEMBLOCK_INIT_MEMORY_REGION_COUNT];
|
||||
static struct memblock_region init_reserved_regions[MEMBLOCK_INIT_RESERVED_REGION_COUNT];
|
||||
static struct memblock_region
|
||||
init_memory_regions[MEMBLOCK_INIT_MEMORY_REGION_COUNT];
|
||||
static struct memblock_region
|
||||
init_reserved_regions[MEMBLOCK_INIT_RESERVED_REGION_COUNT];
|
||||
|
||||
static phys_addr_t do_alloc(size_t size, phys_addr_t align);
|
||||
|
||||
@@ -59,16 +61,21 @@ static void memblock_double_capacity(struct memblock_type *type)
|
||||
{
|
||||
size_t new_max = type->max * 2;
|
||||
|
||||
phys_addr_t new_regions_p = do_alloc(new_max * sizeof(struct memblock_region), 8);
|
||||
phys_addr_t new_regions_p
|
||||
= do_alloc(new_max * sizeof(struct memblock_region), 8);
|
||||
|
||||
void *new_regions = (void *)(new_regions_p + memblock.m_voffset);
|
||||
memcpy(new_regions, type->regions, type->count * sizeof(struct memblock_region));
|
||||
memcpy(new_regions,
|
||||
type->regions,
|
||||
type->count * sizeof(struct memblock_region));
|
||||
|
||||
type->regions = new_regions;
|
||||
type->max = new_max;
|
||||
}
|
||||
|
||||
static int memblock_insert_region(struct memblock_type *type, struct memblock_region *to_add)
|
||||
static int memblock_insert_region(
|
||||
struct memblock_type *type,
|
||||
struct memblock_region *to_add)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
@@ -110,13 +117,17 @@ static int memblock_remove_region(struct memblock_type *type, unsigned int i)
|
||||
int memblock_init(uintptr_t alloc_start, uintptr_t alloc_end, uintptr_t voffset)
|
||||
{
|
||||
memblock.m_alloc_start = alloc_start;
|
||||
memblock.m_alloc_end =alloc_end;
|
||||
memblock.m_alloc_end = alloc_end;
|
||||
memblock.m_voffset = voffset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int memblock_add_range(struct memblock_type *type, uintptr_t base, size_t size, enum memblock_region_status status)
|
||||
int memblock_add_range(
|
||||
struct memblock_type *type,
|
||||
uintptr_t base,
|
||||
size_t size,
|
||||
enum memblock_region_status status)
|
||||
{
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
@@ -131,14 +142,17 @@ int memblock_add_range(struct memblock_type *type, uintptr_t base, size_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct memblock_region new_region = { .base = base, .limit = limit, .status = status };
|
||||
struct memblock_region new_region
|
||||
= {.base = base, .limit = limit, .status = status};
|
||||
|
||||
/* two regions with different statuses CANNOT intersect. we first need to check
|
||||
to make sure the region being added doesn't violate this rule. */
|
||||
/* two regions with different statuses CANNOT intersect. we first need
|
||||
to check to make sure the region being added doesn't violate this
|
||||
rule. */
|
||||
for (unsigned int i = 0; i < type->count; i++) {
|
||||
struct memblock_region *cur_region = &type->regions[i];
|
||||
|
||||
if (new_region.base > cur_region->limit || new_region.limit < cur_region->base) {
|
||||
if (new_region.base > cur_region->limit
|
||||
|| new_region.limit < cur_region->base) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -154,47 +168,67 @@ int memblock_add_range(struct memblock_type *type, uintptr_t base, size_t size,
|
||||
for (unsigned int i = 0; i < type->count; i++) {
|
||||
struct memblock_region *cur_region = &type->regions[i];
|
||||
|
||||
/* case 1: the region being added and the current region have no connection what-so-ever (no overlaps) */
|
||||
if (cur_region->limit + 1 < new_region.base || cur_region->base > new_region.limit) {
|
||||
/* case 1: the region being added and the current region have no
|
||||
* connection what-so-ever (no overlaps) */
|
||||
if (cur_region->limit + 1 < new_region.base
|
||||
|| cur_region->base > new_region.limit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* case 2: the region being added matches a region already in the list. */
|
||||
if (cur_region->base == new_region.base && cur_region->limit == new_region.limit) {
|
||||
/* case 2: the region being added matches a region already in
|
||||
* the list. */
|
||||
if (cur_region->base == new_region.base
|
||||
&& cur_region->limit == new_region.limit) {
|
||||
/* nothing needs to be done */
|
||||
add_new = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* case 3: the region being added completely contains a region already in the list. */
|
||||
if (cur_region->base > new_region.base && cur_region->limit <= new_region.limit) {
|
||||
/* case 3: the region being added completely contains a region
|
||||
* already in the list. */
|
||||
if (cur_region->base > new_region.base
|
||||
&& cur_region->limit <= new_region.limit) {
|
||||
memblock_remove_region(type, i);
|
||||
|
||||
/* after memblock_remove_region(), a different region will have moved into the array slot referenced by i.
|
||||
decrementing i means we'll stay at the current index and process this region. */
|
||||
/* after memblock_remove_region(), a different region
|
||||
will have moved into the array slot referenced by i.
|
||||
decrementing i means we'll stay at the current index
|
||||
and process this region. */
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* case 4: the region being added meets or partially overlaps a
|
||||
* region already in the list. */
|
||||
|
||||
/* case 4: the region being added meets or partially overlaps a region already in the list. */
|
||||
|
||||
/* there can be an overlap at the beginning and the end of the region being added,
|
||||
anything else is either a full overlap (case 3) or not within the region being added at all.
|
||||
to handle this, remove the region that's already in the list and extend the region being added to cover it.
|
||||
the two regions may overlap and have incompatible statuses, but this case was handled earlier in this function. */
|
||||
if ((new_region.base > cur_region->base || new_region.base == cur_region->limit - 1) && new_region.status == cur_region->status) {
|
||||
/* the new region overlaps the END of the current region, change the base of the new region to match that of the current region. */
|
||||
/* there can be an overlap at the beginning and the end of the
|
||||
region being added, anything else is either a full overlap
|
||||
(case 3) or not within the region being added at all. to
|
||||
handle this, remove the region that's already in the list and
|
||||
extend the region being added to cover it. the two regions
|
||||
may overlap and have incompatible statuses, but this case was
|
||||
handled earlier in this function. */
|
||||
if ((new_region.base > cur_region->base
|
||||
|| new_region.base == cur_region->limit - 1)
|
||||
&& new_region.status == cur_region->status) {
|
||||
/* the new region overlaps the END of the current
|
||||
* region, change the base of the new region to match
|
||||
* that of the current region. */
|
||||
new_region.base = cur_region->base;
|
||||
} else if ((new_region.base < cur_region->base || new_region.limit + 1 == cur_region->base) && new_region.status == cur_region->status) {
|
||||
/* the new region overlaps the BEGINNING of the current region, change the limit of the new region to match that of the current region. */
|
||||
} else if (
|
||||
(new_region.base < cur_region->base
|
||||
|| new_region.limit + 1 == cur_region->base)
|
||||
&& new_region.status == cur_region->status) {
|
||||
/* the new region overlaps the BEGINNING of the current
|
||||
* region, change the limit of the new region to match
|
||||
* that of the current region. */
|
||||
new_region.limit = cur_region->limit;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* with the new region updated to include the current region, we can remove the current region from the list */
|
||||
/* with the new region updated to include the current region, we
|
||||
* can remove the current region from the list */
|
||||
memblock_remove_region(type, i);
|
||||
i--;
|
||||
}
|
||||
@@ -216,7 +250,11 @@ int memblock_add(uintptr_t base, size_t size)
|
||||
memblock_double_capacity(&memblock.memory);
|
||||
}
|
||||
|
||||
return memblock_add_range(&memblock.memory, base, size, MEMBLOCK_MEMORY);
|
||||
return memblock_add_range(
|
||||
&memblock.memory,
|
||||
base,
|
||||
size,
|
||||
MEMBLOCK_MEMORY);
|
||||
}
|
||||
|
||||
int memblock_reserve(uintptr_t base, size_t size)
|
||||
@@ -225,7 +263,11 @@ int memblock_reserve(uintptr_t base, size_t size)
|
||||
memblock_double_capacity(&memblock.reserved);
|
||||
}
|
||||
|
||||
return memblock_add_range(&memblock.reserved, base, size, MEMBLOCK_RESERVED);
|
||||
return memblock_add_range(
|
||||
&memblock.reserved,
|
||||
base,
|
||||
size,
|
||||
MEMBLOCK_RESERVED);
|
||||
}
|
||||
|
||||
static phys_addr_t do_alloc(size_t size, phys_addr_t align)
|
||||
@@ -245,7 +287,8 @@ static phys_addr_t do_alloc(size_t size, phys_addr_t align)
|
||||
phys_addr_t region_end = memblock.m_alloc_end - memblock.m_voffset;
|
||||
|
||||
struct memblock_iter it;
|
||||
for_each_free_mem_range (&it, region_start, region_end) {
|
||||
for_each_free_mem_range(&it, region_start, region_end)
|
||||
{
|
||||
phys_addr_t base = it.it_base;
|
||||
if (base & (align - 1)) {
|
||||
base &= ~(align - 1);
|
||||
@@ -270,7 +313,11 @@ static phys_addr_t do_alloc(size_t size, phys_addr_t align)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int status = memblock_add_range(&memblock.reserved, allocated_base, allocated_limit - allocated_base, MEMBLOCK_ALLOC);
|
||||
int status = memblock_add_range(
|
||||
&memblock.reserved,
|
||||
allocated_base,
|
||||
allocated_limit - allocated_base,
|
||||
MEMBLOCK_ALLOC);
|
||||
if (status != 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -312,9 +359,11 @@ int memblock_free_phys(phys_addr_t addr, size_t size)
|
||||
}
|
||||
|
||||
void __next_memory_region(
|
||||
struct memblock_iter *it,
|
||||
struct memblock_type *type_a, struct memblock_type *type_b,
|
||||
uintptr_t start, uintptr_t end)
|
||||
struct memblock_iter *it,
|
||||
struct memblock_type *type_a,
|
||||
struct memblock_type *type_b,
|
||||
uintptr_t start,
|
||||
uintptr_t end)
|
||||
{
|
||||
unsigned int idx_a = IDX_A(it->__idx);
|
||||
unsigned int idx_b = IDX_B(it->__idx);
|
||||
@@ -344,70 +393,85 @@ void __next_memory_region(
|
||||
}
|
||||
|
||||
if (m_start > end) {
|
||||
/* we have gone past the requested memory range and can now stop */
|
||||
/* we have gone past the requested memory range and can
|
||||
* now stop */
|
||||
break;
|
||||
}
|
||||
|
||||
for (; idx_b < type_b->count + 1; idx_b++) {
|
||||
struct memblock_region *r = &type_b->regions[idx_b];
|
||||
|
||||
/* r_start and r_end delimit the region of memory between the current and previous reserved regions.
|
||||
if we have gone past the last reserved region, these variables delimit the range between the end
|
||||
of the last reserved region and the end of memory. */
|
||||
/* r_start and r_end delimit the region of memory
|
||||
between the current and previous reserved regions. if
|
||||
we have gone past the last reserved region, these
|
||||
variables delimit the range between the end of the
|
||||
last reserved region and the end of memory. */
|
||||
uintptr_t r_start = idx_b > 0 ? r[-1].limit + 1 : 0;
|
||||
uintptr_t r_end;
|
||||
|
||||
if (idx_b < type_b->count) {
|
||||
r_end = r->base;
|
||||
|
||||
/* we decrement r_end to get the address of the last byte of the free region.
|
||||
if r_end is already zero, there is a reserved region starting at address 0x0.
|
||||
as long as r_end == r_start == 0x00000, we will skip this region. */
|
||||
/* we decrement r_end to get the address of the
|
||||
last byte of the free region. if r_end is
|
||||
already zero, there is a reserved region
|
||||
starting at address 0x0. as long as r_end ==
|
||||
r_start == 0x00000, we will skip this region.
|
||||
*/
|
||||
if (r_end) {
|
||||
r_end--;
|
||||
}
|
||||
} else {
|
||||
/* this maximum value will be clamped to the bounds of memblock.memory
|
||||
before being returned to the caller */
|
||||
/* this maximum value will be clamped to the
|
||||
bounds of memblock.memory before being
|
||||
returned to the caller */
|
||||
r_end = ADDR_MAX;
|
||||
}
|
||||
|
||||
if (r_start >= r_end) {
|
||||
/* this free region has a length of zero, move to the next one */
|
||||
/* this free region has a length of zero, move
|
||||
* to the next one */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r_start >= m_end) {
|
||||
/* we've gone past the end of the current memory region, and need to go to the next one */
|
||||
/* we've gone past the end of the current memory
|
||||
* region, and need to go to the next one */
|
||||
break;
|
||||
}
|
||||
|
||||
/* we've already gone past this free memory region. move to the next one */
|
||||
/* we've already gone past this free memory region. move
|
||||
* to the next one */
|
||||
if (m_start >= r_end) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we want the area that is overlapped by both
|
||||
region M (m_start - m_end) : The region defined as system memory.
|
||||
region R (r_start - r_end) : The region defined as free / outside of any reserved regions.
|
||||
region M (m_start - m_end) : The region defined
|
||||
as system memory. region R (r_start - r_end) : The
|
||||
region defined as free / outside of any reserved
|
||||
regions.
|
||||
*/
|
||||
it->it_base = MAX(m_start, r_start);
|
||||
it->it_limit = MIN(m_end, r_end);
|
||||
|
||||
/* further limit the region to the intersection between the region itself and the
|
||||
specified iteration bounds */
|
||||
/* further limit the region to the intersection between
|
||||
the region itself and the specified iteration bounds
|
||||
*/
|
||||
it->it_base = MAX(it->it_base, start);
|
||||
it->it_limit = MIN(it->it_limit, end);
|
||||
|
||||
if (it->it_limit <= it->it_base) {
|
||||
/* this region is not part of the specified bounds, skip it. */
|
||||
/* this region is not part of the specified
|
||||
* bounds, skip it. */
|
||||
continue;
|
||||
}
|
||||
|
||||
it->it_status = MEMBLOCK_MEMORY;
|
||||
|
||||
/* whichever region is smaller, increment the pointer for that type, so we can
|
||||
compare the larger region with the next region of the incremented type. */
|
||||
/* whichever region is smaller, increment the pointer
|
||||
for that type, so we can compare the larger region
|
||||
with the next region of the incremented type. */
|
||||
if (m_end <= r_end) {
|
||||
idx_a++;
|
||||
} else {
|
||||
|
||||
60
vm/page.c
60
vm/page.c
@@ -1,41 +1,41 @@
|
||||
#include <mango/types.h>
|
||||
#include <mango/libc/string.h>
|
||||
#include <mango/memblock.h>
|
||||
#include <mango/printk.h>
|
||||
#include <mango/types.h>
|
||||
#include <mango/vm.h>
|
||||
#include <mango/libc/string.h>
|
||||
|
||||
/* Pre-calculated page order -> size conversion table */
|
||||
static size_t page_order_bytes[] = {
|
||||
[VM_PAGE_4K] = 0x1000,
|
||||
[VM_PAGE_8K] = 0x2000,
|
||||
[VM_PAGE_16K] = 0x4000,
|
||||
[VM_PAGE_32K] = 0x8000,
|
||||
[VM_PAGE_64K] = 0x10000,
|
||||
[VM_PAGE_4K] = 0x1000,
|
||||
[VM_PAGE_8K] = 0x2000,
|
||||
[VM_PAGE_16K] = 0x4000,
|
||||
[VM_PAGE_32K] = 0x8000,
|
||||
[VM_PAGE_64K] = 0x10000,
|
||||
[VM_PAGE_128K] = 0x20000,
|
||||
[VM_PAGE_256K] = 0x40000,
|
||||
[VM_PAGE_512K] = 0x80000,
|
||||
[VM_PAGE_1M] = 0x100000,
|
||||
[VM_PAGE_2M] = 0x200000,
|
||||
[VM_PAGE_4M] = 0x400000,
|
||||
[VM_PAGE_8M] = 0x800000,
|
||||
[VM_PAGE_16M] = 0x1000000,
|
||||
[VM_PAGE_32M] = 0x2000000,
|
||||
[VM_PAGE_64M] = 0x4000000,
|
||||
[VM_PAGE_1M] = 0x100000,
|
||||
[VM_PAGE_2M] = 0x200000,
|
||||
[VM_PAGE_4M] = 0x400000,
|
||||
[VM_PAGE_8M] = 0x800000,
|
||||
[VM_PAGE_16M] = 0x1000000,
|
||||
[VM_PAGE_32M] = 0x2000000,
|
||||
[VM_PAGE_64M] = 0x4000000,
|
||||
[VM_PAGE_128M] = 0x8000000,
|
||||
|
||||
/* vm can support pages of this size, but
|
||||
struct vm_page only has 4 bits with which to store
|
||||
the page order, which cannot accomodate these
|
||||
larger order numbers */
|
||||
struct vm_page only has 4 bits with which to store
|
||||
the page order, which cannot accomodate these
|
||||
larger order numbers */
|
||||
[VM_PAGE_256M] = 0x10000000,
|
||||
[VM_PAGE_512M] = 0x20000000,
|
||||
[VM_PAGE_1G] = 0x40000000,
|
||||
[VM_PAGE_2G] = 0x80000000,
|
||||
[VM_PAGE_4G] = 0x100000000,
|
||||
[VM_PAGE_8G] = 0x200000000,
|
||||
[VM_PAGE_16G] = 0x400000000,
|
||||
[VM_PAGE_32G] = 0x800000000,
|
||||
[VM_PAGE_64G] = 0x1000000000,
|
||||
[VM_PAGE_1G] = 0x40000000,
|
||||
[VM_PAGE_2G] = 0x80000000,
|
||||
[VM_PAGE_4G] = 0x100000000,
|
||||
[VM_PAGE_8G] = 0x200000000,
|
||||
[VM_PAGE_16G] = 0x400000000,
|
||||
[VM_PAGE_32G] = 0x800000000,
|
||||
[VM_PAGE_64G] = 0x1000000000,
|
||||
};
|
||||
|
||||
phys_addr_t vm_virt_to_phys(void *p)
|
||||
@@ -56,7 +56,8 @@ phys_addr_t vm_virt_to_phys(void *p)
|
||||
|
||||
void *vm_phys_to_virt(phys_addr_t p)
|
||||
{
|
||||
if (p >= (memblock.m_alloc_start - memblock.m_voffset) && p < (memblock.m_alloc_end - memblock.m_voffset)) {
|
||||
if (p >= (memblock.m_alloc_start - memblock.m_voffset)
|
||||
&& p < (memblock.m_alloc_end - memblock.m_voffset)) {
|
||||
return memblock_phys_to_virt(p);
|
||||
}
|
||||
|
||||
@@ -124,11 +125,10 @@ vm_alignment_t vm_page_order_to_alignment(enum vm_page_order order)
|
||||
return ~(page_order_bytes[order] - 1);
|
||||
}
|
||||
|
||||
|
||||
size_t vm_bytes_to_pages(size_t bytes)
|
||||
{
|
||||
if (bytes & (VM_PAGE_SIZE-1)) {
|
||||
bytes &= ~(VM_PAGE_SIZE-1);
|
||||
if (bytes & (VM_PAGE_SIZE - 1)) {
|
||||
bytes &= ~(VM_PAGE_SIZE - 1);
|
||||
bytes += VM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,6 @@ struct vm_zone *vm_page_get_zone(struct vm_page *pg)
|
||||
return &node->pg_zones[pg->p_zone];
|
||||
}
|
||||
|
||||
|
||||
struct vm_page *vm_page_alloc(enum vm_page_order order, enum vm_flags flags)
|
||||
{
|
||||
/* TODO prefer nodes closer to us */
|
||||
@@ -232,7 +231,8 @@ struct vm_page *vm_page_merge(struct vm_page *a, struct vm_page *b)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((a->p_flags & (VM_PAGE_ALLOC | VM_PAGE_RESERVED)) != (b->p_flags & (VM_PAGE_ALLOC | VM_PAGE_RESERVED))) {
|
||||
if ((a->p_flags & (VM_PAGE_ALLOC | VM_PAGE_RESERVED))
|
||||
!= (b->p_flags & (VM_PAGE_ALLOC | VM_PAGE_RESERVED))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
93
vm/sparse.c
93
vm/sparse.c
@@ -22,13 +22,13 @@
|
||||
of the sparse memory model may be outweighed by the extra
|
||||
overhead, and the flat memory model may be a better choice.
|
||||
*/
|
||||
#include <mango/vm.h>
|
||||
#include <mango/arg.h>
|
||||
#include <mango/printk.h>
|
||||
#include <mango/panic.h>
|
||||
#include <mango/memblock.h>
|
||||
#include <mango/util.h>
|
||||
#include <mango/machine/cpu.h>
|
||||
#include <mango/memblock.h>
|
||||
#include <mango/panic.h>
|
||||
#include <mango/printk.h>
|
||||
#include <mango/util.h>
|
||||
#include <mango/vm.h>
|
||||
|
||||
static struct vm_sector *sector_array = NULL;
|
||||
static size_t sector_array_count = 0;
|
||||
@@ -53,11 +53,16 @@ static enum sector_coverage_mode get_sector_coverage_mode(void)
|
||||
return SECTOR_COVERAGE_ALL;
|
||||
}
|
||||
|
||||
printk("vm: [sparse] ignoring unknown sector coverage mode '%s', using FREE", arg);
|
||||
printk("vm: [sparse] ignoring unknown sector coverage mode '%s', using "
|
||||
"FREE",
|
||||
arg);
|
||||
return SECTOR_COVERAGE_FREE;
|
||||
}
|
||||
|
||||
static struct vm_sector *phys_addr_to_sector_and_index(phys_addr_t addr, size_t *sector_id, size_t *index)
|
||||
static struct vm_sector *phys_addr_to_sector_and_index(
|
||||
phys_addr_t addr,
|
||||
size_t *sector_id,
|
||||
size_t *index)
|
||||
{
|
||||
/* all sectors have the same size */
|
||||
size_t step = vm_page_order_to_bytes(sector_array[0].s_size);
|
||||
@@ -98,7 +103,6 @@ static struct vm_page *get_or_create_page(phys_addr_t addr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sector->s_pages[page_number].p_sector = sector_number;
|
||||
return §or->s_pages[page_number];
|
||||
}
|
||||
@@ -123,9 +127,13 @@ static enum vm_page_order find_minimum_sector_size(phys_addr_t pmem_end)
|
||||
are in need of improvement to ensure that sparse works well on a wide
|
||||
range of systems. */
|
||||
static void calculate_sector_size_and_count(
|
||||
size_t last_reserved_pfn, size_t last_free_pfn, size_t limit_pfn,
|
||||
size_t reserved_size, size_t free_size,
|
||||
unsigned int *out_sector_count, enum vm_page_order *out_sector_size)
|
||||
size_t last_reserved_pfn,
|
||||
size_t last_free_pfn,
|
||||
size_t limit_pfn,
|
||||
size_t reserved_size,
|
||||
size_t free_size,
|
||||
unsigned int *out_sector_count,
|
||||
enum vm_page_order *out_sector_size)
|
||||
{
|
||||
/* we can support up to VM_MAX_SECTORS memory sectors.
|
||||
the minimum sector size is what ever is required
|
||||
@@ -154,8 +162,8 @@ static void calculate_sector_size_and_count(
|
||||
threshold. */
|
||||
sector_size++;
|
||||
|
||||
/* if the difference is particularly big, increase the sector size
|
||||
even further */
|
||||
/* if the difference is particularly big, increase the sector
|
||||
size even further */
|
||||
if (memdiff >= 0x1000000) {
|
||||
sector_size++;
|
||||
}
|
||||
@@ -183,13 +191,15 @@ void vm_sparse_init(void)
|
||||
size_t last_reserved_pfn = 0, last_free_pfn = 0;
|
||||
|
||||
struct memblock_iter it;
|
||||
for_each_mem_range (&it, 0x0, UINTPTR_MAX) {
|
||||
for_each_mem_range(&it, 0x0, UINTPTR_MAX)
|
||||
{
|
||||
if (pmem_limit < it.it_limit + 1) {
|
||||
pmem_limit = it.it_limit + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_free_mem_range (&it, 0x0, UINTPTR_MAX) {
|
||||
for_each_free_mem_range(&it, 0x0, UINTPTR_MAX)
|
||||
{
|
||||
free_size += it.it_limit - it.it_base + 1;
|
||||
|
||||
size_t last_pfn = it.it_limit / VM_PAGE_SIZE;
|
||||
@@ -199,7 +209,8 @@ void vm_sparse_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
for_each_reserved_mem_range (&it, 0x0, UINTPTR_MAX) {
|
||||
for_each_reserved_mem_range(&it, 0x0, UINTPTR_MAX)
|
||||
{
|
||||
reserved_size += it.it_limit - it.it_base + 1;
|
||||
|
||||
size_t last_pfn = it.it_limit / VM_PAGE_SIZE;
|
||||
@@ -212,7 +223,8 @@ void vm_sparse_init(void)
|
||||
enum sector_coverage_mode mode = get_sector_coverage_mode();
|
||||
phys_addr_t pmem_end = 0;
|
||||
|
||||
enum vm_page_order sector_size = find_minimum_sector_size(last_free_pfn);
|
||||
enum vm_page_order sector_size
|
||||
= find_minimum_sector_size(last_free_pfn);
|
||||
if (mode == SECTOR_COVERAGE_FREE) {
|
||||
pmem_end = last_free_pfn * VM_PAGE_SIZE;
|
||||
} else {
|
||||
@@ -224,50 +236,63 @@ void vm_sparse_init(void)
|
||||
size_t sector_bytes = 0;
|
||||
unsigned int nr_sectors = 0;
|
||||
calculate_sector_size_and_count(
|
||||
last_reserved_pfn, last_free_pfn, pmem_end / VM_PAGE_SIZE,
|
||||
reserved_size, free_size,
|
||||
&nr_sectors, §or_size);
|
||||
last_reserved_pfn,
|
||||
last_free_pfn,
|
||||
pmem_end / VM_PAGE_SIZE,
|
||||
reserved_size,
|
||||
free_size,
|
||||
&nr_sectors,
|
||||
§or_size);
|
||||
sector_bytes = vm_page_order_to_bytes(sector_size);
|
||||
|
||||
char sector_size_str[64];
|
||||
data_size_to_string(sector_bytes, sector_size_str, sizeof sector_size_str);
|
||||
data_size_to_string(
|
||||
sector_bytes,
|
||||
sector_size_str,
|
||||
sizeof sector_size_str);
|
||||
|
||||
sector_array = kzalloc(sizeof(struct vm_sector) * nr_sectors, 0);
|
||||
sector_array_count = nr_sectors;
|
||||
|
||||
for (unsigned int i = 0; i < nr_sectors; i++) {
|
||||
sector_array[i].s_size = sector_size;
|
||||
sector_array[i].s_first_pfn = (i * sector_bytes) >> VM_PAGE_SHIFT;
|
||||
sector_array[i].s_first_pfn
|
||||
= (i * sector_bytes) >> VM_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
size_t s, i;
|
||||
phys_addr_to_sector_and_index(0x3f00000, &s, &i);
|
||||
|
||||
for_each_free_mem_range(&it, 0x0, pmem_end) {
|
||||
for_each_free_mem_range(&it, 0x0, pmem_end)
|
||||
{
|
||||
if (it.it_base & VM_PAGE_MASK) {
|
||||
it.it_base &= ~VM_PAGE_MASK;
|
||||
it.it_base += VM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
for (uintptr_t i = it.it_base; i < it.it_limit; i += VM_PAGE_SIZE) {
|
||||
for (phys_addr_t i = it.it_base; i < it.it_limit;
|
||||
i += VM_PAGE_SIZE) {
|
||||
struct vm_page *pg = get_or_create_page(i);
|
||||
pg->p_flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_reserved_mem_range(&it, 0x0, pmem_end) {
|
||||
for_each_reserved_mem_range(&it, 0x0, pmem_end)
|
||||
{
|
||||
if (it.it_base & VM_PAGE_MASK) {
|
||||
it.it_base &= ~VM_PAGE_MASK;
|
||||
it.it_base += VM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
for (uintptr_t i = it.it_base; i < it.it_limit; i += VM_PAGE_SIZE) {
|
||||
for (phys_addr_t i = it.it_base; i < it.it_limit;
|
||||
i += VM_PAGE_SIZE) {
|
||||
struct vm_page *pg = vm_page_get(i);
|
||||
|
||||
if (!pg) {
|
||||
/* if the page doesn't exist, it is part of a sector
|
||||
that only contains reserved pages. a NULL page
|
||||
is implicitly treated as reserved */
|
||||
/* if the page doesn't exist, it is part of a
|
||||
sector that only contains reserved pages. a
|
||||
NULL page is implicitly treated as reserved
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -275,7 +300,9 @@ void vm_sparse_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
printk("vm: [sparse] initialised %zu sectors of size %s", nr_sectors, sector_size_str);
|
||||
printk("vm: [sparse] initialised %zu sectors of size %s",
|
||||
nr_sectors,
|
||||
sector_size_str);
|
||||
}
|
||||
|
||||
struct vm_page *vm_page_get_sparse(phys_addr_t addr)
|
||||
@@ -288,7 +315,8 @@ struct vm_page *vm_page_get_sparse(phys_addr_t addr)
|
||||
|
||||
struct vm_sector *sector = §or_array[sector_number];
|
||||
|
||||
if (!sector->s_pages || page_number >= vm_page_order_to_pages(sector->s_size)) {
|
||||
if (!sector->s_pages
|
||||
|| page_number >= vm_page_order_to_pages(sector->s_size)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -298,5 +326,6 @@ struct vm_page *vm_page_get_sparse(phys_addr_t addr)
|
||||
size_t vm_page_get_pfn_sparse(struct vm_page *pg)
|
||||
{
|
||||
struct vm_sector *sector = §or_array[pg->p_sector];
|
||||
return sector->s_first_pfn + (((uintptr_t)pg - (uintptr_t)sector->s_pages) / sizeof *pg);
|
||||
return sector->s_first_pfn
|
||||
+ (((uintptr_t)pg - (uintptr_t)sector->s_pages) / sizeof *pg);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user