Skip to content

Commit

Permalink
fix some pmm bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
brvtalcake committed Oct 31, 2024
1 parent 1030091 commit 01bf0ae
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 30 deletions.
79 changes: 65 additions & 14 deletions zerOS/include/kernel/data/bitset.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@

#if !defined(zerOS_KERNEL_DATA_BITSET_H_INCLUDED) || defined(zerOS_NEED_BITSET_IMPLEMENTATION)

#undef __bitset_underlying_type_set_vectorized
#ifndef zerOS_BITSET_UNDERLYING_TYPE
#define zerOS_BITSET_UNDERLYING_TYPE zerOS_fast_uint_t
#define zerOS_BITSET_UNDERLYING_TYPE zerOS_fast_uint_t
#define __bitset_underlying_type_set_vectorized(...) zerOS_fast_uint_set_vectorized(__VA_ARGS__)
#elif defined(zerOS_BITSET_UNDERLYING_TYPE_SET_VECTORIZED_FN)
#define __bitset_underlying_type_set_vectorized(...) zerOS_BITSET_UNDERLYING_TYPE_SET_VECTORIZED_FN(__VA_ARGS__)
#else
#define __bitset_underlying_type_set_vectorized(...)
#endif

static_assert(
Expand All @@ -26,35 +32,80 @@ typedef zerOS_BITSET_UNDERLYING_TYPE* bitset_t;
// TODO: Make `set_all` and `clear_all` functions accept the size of bits instead of the size of zerOS_BITSET_UNDERLYING_TYPE
// composing the bitset

static inline void zerOS_bitset_set(bitset_t bitset, size_t bit)
static inline void zerOS_bitset_set(bitset_t bitset, const size_t bit)
{
size_t index = bit / zerOS_fast_uint_bits;
size_t offset = bit % zerOS_fast_uint_bits;
const size_t underlying_bits = sizeof(zerOS_BITSET_UNDERLYING_TYPE) * __CHAR_BIT__;

const size_t index = bit / underlying_bits;
const size_t offset = bit % underlying_bits;

bitset[index] |= (zerOS_BITSET_UNDERLYING_TYPE)1 << offset;
}

static inline void zerOS_bitset_clear(bitset_t bitset, size_t bit)
static inline void zerOS_bitset_clear(bitset_t bitset, const size_t bit)
{
size_t index = bit / zerOS_fast_uint_bits;
size_t offset = bit % zerOS_fast_uint_bits;
const size_t underlying_bits = sizeof(zerOS_BITSET_UNDERLYING_TYPE) * __CHAR_BIT__;

const size_t index = bit / underlying_bits;
const size_t offset = bit % underlying_bits;

bitset[index] &= ~((zerOS_BITSET_UNDERLYING_TYPE)1 << offset);
}

static inline bool zerOS_bitset_test(bitset_t bitset, size_t bit)
static inline bool zerOS_bitset_test(bitset_t bitset, const size_t bit)
{
size_t index = bit / zerOS_fast_uint_bits;
size_t offset = bit % zerOS_fast_uint_bits;
const size_t underlying_bits = sizeof(zerOS_BITSET_UNDERLYING_TYPE) * __CHAR_BIT__;

const size_t index = bit / underlying_bits;
const size_t offset = bit % underlying_bits;

return bitset[index] & ((zerOS_BITSET_UNDERLYING_TYPE)1 << offset);
}

static inline void zerOS_bitset_set_all(bitset_t bitset, size_t size)
/**
* @brief Set all bits in the bitset.
* @param bitset The bitset.
* @param size Number of bits in the bitset (1-based maximum bit index).
*/
static inline void zerOS_bitset_set_all(bitset_t bitset, const size_t size)
{
zerOS_fast_uint_set_vectorized(bitset, size, (zerOS_BITSET_UNDERLYING_TYPE)-1);
const size_t underlying_bits = sizeof(zerOS_BITSET_UNDERLYING_TYPE) * __CHAR_BIT__;
// Round up, to fill the last element completely, even though it may not be fully used
const size_t realsize = (size + underlying_bits - 1) / underlying_bits;
const zerOS_BITSET_UNDERLYING_TYPE value = (zerOS_BITSET_UNDERLYING_TYPE)-1;

#if !(ISEMPTY(__bitset_underlying_type_set_vectorized(_x, _x, _x))) && \
defined(__bitset_underlying_type_set_vectorized)
__bitset_underlying_type_set_vectorized(
bitset, realsize, value
);
#else
for (size_t i = 0; i < realsize; i++)
bitset[i] = value;
#endif
}

static inline void zerOS_bitset_clear_all(bitset_t bitset, size_t size)
/**
* @brief Clear all bits in the bitset.
* @param bitset The bitset.
* @param size Number of bits in the bitset (1-based maximum bit index).
*/
static inline void zerOS_bitset_clear_all(bitset_t bitset, const size_t size)
{
zerOS_fast_uint_set_vectorized(bitset, size, (zerOS_BITSET_UNDERLYING_TYPE)0);
const size_t underlying_bits = sizeof(zerOS_BITSET_UNDERLYING_TYPE) * __CHAR_BIT__;
// Round up, to fill the last element completely, even though it may not be fully used
const size_t realsize = (size + underlying_bits - 1) / underlying_bits;
const zerOS_BITSET_UNDERLYING_TYPE value = (zerOS_BITSET_UNDERLYING_TYPE)0;

#if !(ISEMPTY(__bitset_underlying_type_set_vectorized(_x, _x, _x))) && \
defined(__bitset_underlying_type_set_vectorized)
__bitset_underlying_type_set_vectorized(
bitset, realsize, value
);
#else
for (size_t i = 0; i < realsize; i++)
bitset[i] = value;
#endif
}

#endif
Expand Down
38 changes: 23 additions & 15 deletions zerOS/include/machine/alderlake/fast_data_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,70 @@
#include <machine/common/x86_64.h>

// TODO: Implement the following function with AVX2 instead
static inline void zerOS_fast_uint_set_vectorized(zerOS_fast_uint_t* array, size_t size, zerOS_fast_uint_t value)
/**
* @brief Set all elements of an array of `length` elements of type `zerOS_fast_uint_t` to a given value, possibly using vectorized instructions.
*
* @param array The array to set.
* @param length The length of the array.
* @param value The value to set the array to.
*/
static void zerOS_fast_uint_set_vectorized(zerOS_fast_uint_t* array, size_t length, zerOS_fast_uint_t value)
{
size_t remaining = length;
if (FAST_UINT_BITS(32))
{
const __m128i vector_value = _mm_set1_epi32(value);
zerOS_fast_uint_t* array_aligned_up = (zerOS_fast_uint_t*)((uintptr_t)array & ~(16 - 1));
zerOS_fast_uint_t* array_aligned_up = (zerOS_fast_uint_t*)((uintptr_t)array & ~((uintptr_t)16U - 1));

// Fill the unaligned part
while ((uintptr_t)array < (uintptr_t)array_aligned_up && size)
while ((uintptr_t)array < (uintptr_t)array_aligned_up && remaining)
{
*array++ = value;
size--;
remaining--;
}

// Fill the aligned part
while (size >= 4)
while (remaining >= 4)
{
_mm_store_si128((__m128i*)array, vector_value);
array += 4;
size -= 4;
remaining -= 4;
}

// Fill the unaligned part
while (size)
while (remaining)
{
*array++ = value;
size--;
remaining--;
}

return;
}
else if (FAST_UINT_BITS(64))
{
const __m128i vector_value = _mm_set1_epi64x(value);
zerOS_fast_uint_t* array_aligned_up = (zerOS_fast_uint_t*)((uintptr_t)array & ~(16 - 1));
zerOS_fast_uint_t* array_aligned_up = (zerOS_fast_uint_t*)((uintptr_t)array & ~((uintptr_t)16U - 1));

// Fill the unaligned part
while ((uintptr_t)array < (uintptr_t)array_aligned_up && size)
while ((uintptr_t)array < (uintptr_t)array_aligned_up && remaining)
{
*array++ = value;
size--;
remaining--;
}

// Fill the aligned part
while (size >= 2)
while (remaining >= 2)
{
_mm_store_si128((__m128i*)array, vector_value);
array += 2;
size -= 2;
remaining -= 2;
}

// Fill the unaligned part
while (size)
while (remaining)
{
*array++ = value;
size--;
remaining--;
}

return;
Expand Down
20 changes: 19 additions & 1 deletion zerOS/src/kernel/memory/pmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <klibc/alloca.h>
#include <klibc/string.h>

#if 0
// TODO: Make this struct accept size in number of bits (i.e. number of pages) instead of size in number of zerOS_BITSET_UNDERLYING_TYPE elements
struct pmm_basic_manager
{
Expand All @@ -31,6 +32,17 @@ struct pmm_basic_manager
size_t next_free; ///< The index of the next free page, in the bitmap.
size_t size; ///< The size of the bitmap, in bitmap elements (i.e. page_count / zerOS_fast_uint_bits or size_in_bytes / sizeof(zerOS_fast_uint_t)).
};
#else
struct pmm_basic_manager
{
size_t limine_entry_index; ///< The index of the limine entry.
size_t base_page_index; ///< The index of the first page, in physical memory.
bitset_t bitmap; ///< The bitmap.
bitset_t bitmap_physaddr; ///< The physical address of the bitmap.
size_t next_free; ///< The index of the next free page, in the bitmap.
size_t size; ///< The size of the bitmap, in bits (i.e. page_count or size_in_bytes * __CHAR_BIT__).
};
#endif

static struct pmm_basic_manager pmm_main_managers[zerOS_CONFIG_MAX_USABLE_MEMORY_REGIONS];

Expand Down Expand Up @@ -84,7 +96,7 @@ static void init_basic_managers(
struct pmm_basic_manager* manager = &pmm_main_managers[realind];
manager->limine_entry_index = manageable[realind];
manager->base_page_index = entry->base / zerOS_PAGE_SIZE;
manager->size = needs[realind] / sizeof(zerOS_fast_uint_t);
manager->size = needs[realind] * 8;
manager->bitmap_physaddr = (bitset_t)current_offset;
manager->bitmap = (bitset_t)(hhdm_offset + current_offset);
manager->next_free = 0;
Expand All @@ -97,6 +109,12 @@ static void init_basic_managers(
if (entry == bitmap_entry)
{
const size_t max_managed_page_index = (entry->length / zerOS_PAGE_SIZE);
if (max_managed_page_index != manager->size)
{
zerOS_early_printk("zerOS: logic error: assertion failed\n");
zerOS_hcf();
}

const size_t occupied_pages = (needs_sum / zerOS_PAGE_SIZE) + ((needs_sum % zerOS_PAGE_SIZE) != 0 ? 1 : 0);
for (size_t j = 0; j < occupied_pages; j++)
zerOS_bitset_set(manager->bitmap, j);
Expand Down

0 comments on commit 01bf0ae

Please sign in to comment.