system/boot: add optional alignment to kernel_args_malloc

* A few things need alignment, instead of forcing them all
  to align themselves, support alignment of the kernel_args
* Default of 1 is "no alignment"

Change-Id: Iff05dcec8adaa963c8444d701464ea11616062f6
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4698
Reviewed-by: Alex von Gluck IV <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Alexander von Gluck IV
2021-11-07 09:58:15 +00:00
committed by Adrien Destugues
parent c9d6d52b03
commit 4b5c7fe7e1
5 changed files with 74 additions and 81 deletions
+4 -4
View File
@@ -19,14 +19,14 @@ extern KMessage gBootVolume;
extern "C" { extern "C" {
#endif #endif
extern void *kernel_args_malloc(size_t size);
extern char *kernel_args_strdup(const char *string);
extern void kernel_args_free(void *address);
extern int main(struct stage2_args *args); extern int main(struct stage2_args *args);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
extern void *kernel_args_malloc(size_t size, uint8 alignment = 1);
extern char *kernel_args_strdup(const char *string);
extern void kernel_args_free(void *address);
#endif /* KERNEL_BOOT_STAGE2_H */ #endif /* KERNEL_BOOT_STAGE2_H */
+3 -4
View File
@@ -350,11 +350,10 @@ ucode_load(BootVolume& volume)
} }
ssize_t length = stat.st_size; ssize_t length = stat.st_size;
const uint32 alignment = 16;
#define ALIGN(size, align) (((size) + align - 1) & ~(align - 1)) // 16-byte alignment required
void *buffer = kernel_args_malloc(length + alignment - 1); void *buffer = kernel_args_malloc(length, 16);
if (buffer != NULL) { if (buffer != NULL) {
buffer = (void*)ALIGN((addr_t)buffer, alignment);
if (read(fd, buffer, length) != length) { if (read(fd, buffer, length) != length) {
dprintf("ucode_load: couldn't read microcode file\n"); dprintf("ucode_load: couldn't read microcode file\n");
kernel_args_free(buffer); kernel_args_free(buffer);
+63 -60
View File
@@ -369,68 +369,10 @@ ignore_physical_memory_ranges_beyond_4gb()
// #pragma mark - kernel_args allocations // #pragma mark - kernel_args allocations
/*! This function can be used to allocate memory that is going
to be passed over to the kernel. For example, the preloaded_image
structures are allocated this way.
The boot loader heap doesn't make it into the kernel!
*/
extern "C" void*
kernel_args_malloc(size_t size)
{
//dprintf("kernel_args_malloc(): %ld bytes (%ld bytes left)\n", size, sFree);
if (sFirstFree != NULL && size <= sFree) {
// there is enough space in the current buffer
void* address = sFirstFree;
sFirstFree = (void*)((addr_t)sFirstFree + size);
sLast = address;
sFree -= size;
return address;
}
if (size > kChunkSize / 2 && sFree < size) {
// the block is so large, we'll allocate a new block for it
void* block = NULL;
if (platform_allocate_region(&block, size, B_READ_AREA | B_WRITE_AREA,
false) != B_OK) {
return NULL;
}
// Translate the address if needed on the current platform
addr_t translated_block;
platform_bootloader_address_to_kernel_address(block, &translated_block);
if (add_kernel_args_range((void *)translated_block, size) != B_OK)
panic("kernel_args max range too low!\n");
return block;
}
// just allocate a new block and "close" the old one
void* block = NULL;
if (platform_allocate_region(&block, kChunkSize, B_READ_AREA | B_WRITE_AREA,
false) != B_OK) {
return NULL;
}
sFirstFree = (void*)((addr_t)block + size);
sLast = block;
sFree = kChunkSize - size;
// Translate the address if needed on the current platform
addr_t translated_block;
platform_bootloader_address_to_kernel_address(block, &translated_block);
if (add_kernel_args_range((void *)translated_block, kChunkSize) != B_OK)
panic("kernel_args max range too low!\n");
return block;
}
/*! Convenience function that copies strdup() functions for the /*! Convenience function that copies strdup() functions for the
kernel args heap. kernel args heap.
*/ */
extern "C" char* char*
kernel_args_strdup(const char* string) kernel_args_strdup(const char* string)
{ {
if (string == NULL || string[0] == '\0') if (string == NULL || string[0] == '\0')
@@ -447,11 +389,72 @@ kernel_args_strdup(const char* string)
} }
/*! This function can be used to allocate (optionally aligned) memory that
is going to be passed over to the kernel. For example, the preloaded_image
structures are allocated this way.
The boot loader heap doesn't make it into the kernel!
*/
void*
kernel_args_malloc(size_t size, uint8 alignment)
{
//dprintf("kernel_args_malloc(): %ld bytes (%ld bytes left)\n", size, sFree);
#define ALIGN(addr, align) (((addr) + align - 1) & ~(align - 1))
size_t alignedSize = size + alignment - 1;
if (sFirstFree != NULL && alignedSize <= sFree) {
// there is enough space in the current buffer
void* address = (void*)ALIGN((addr_t)sFirstFree, alignment);
sFirstFree = (void*)((addr_t)sFirstFree + alignedSize);
sLast = address;
sFree -= alignedSize;
return address;
}
if (alignedSize > kChunkSize / 2 && sFree < alignedSize) {
// the block is so large, we'll allocate a new block for it
void* block = NULL;
if (platform_allocate_region(&block, alignedSize,
B_READ_AREA | B_WRITE_AREA, false) != B_OK) {
return NULL;
}
// Translate the address if needed on the current platform
addr_t translated_block;
platform_bootloader_address_to_kernel_address(block, &translated_block);
if (add_kernel_args_range((void *)translated_block, size) != B_OK)
panic("kernel_args max range too low!\n");
return (void*)ALIGN((addr_t)block, alignment);
}
// just allocate a new block and "close" the old one
void* block = NULL;
if (platform_allocate_region(&block, kChunkSize, B_READ_AREA | B_WRITE_AREA,
false) != B_OK) {
return NULL;
}
sFirstFree = (void*)((addr_t)block + alignedSize);
sLast = block;
sFree = kChunkSize - alignedSize;
// Translate the address if needed on the current platform
addr_t translated_block;
platform_bootloader_address_to_kernel_address(block, &translated_block);
if (add_kernel_args_range((void *)translated_block, kChunkSize) != B_OK)
panic("kernel_args max range too low!\n");
return (void*)ALIGN((addr_t)block, alignment);
}
/*! This function frees a block allocated via kernel_args_malloc(). /*! This function frees a block allocated via kernel_args_malloc().
It's very simple; it can only free the last allocation. It's It's very simple; it can only free the last allocation. It's
enough for its current usage in the boot loader, though. enough for its current usage in the boot loader, though.
*/ */
extern "C" void void
kernel_args_free(void* block) kernel_args_free(void* block)
{ {
if (sLast != block) { if (sLast != block) {
+2 -7
View File
@@ -464,13 +464,8 @@ dtb_set_kernel_args()
if (sDtbTable != NULL) { if (sDtbTable != NULL) {
#if defined(__ARM__) || defined(__riscv) #if defined(__ARM__) || defined(__riscv)
// FDT needs to be 8-byte aligned for libfdt // libfdt requires 8-byte alignment
// TODO: we need kernel_args_malloc with alignment! gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(sDtbSize, 8);
#define FDT_ALIGNMENT 8
#define FDT_ALIGN(addr) (((addr) + FDT_ALIGNMENT - 1) & ~(FDT_ALIGNMENT - 1))
gKernelArgs.arch_args.fdt
= (void*)FDT_ALIGN((addr_t)kernel_args_malloc(sDtbSize
+ FDT_ALIGNMENT - 1));
if (gKernelArgs.arch_args.fdt != NULL) if (gKernelArgs.arch_args.fdt != NULL)
memcpy(gKernelArgs.arch_args.fdt, sDtbTable, sDtbSize); memcpy(gKernelArgs.arch_args.fdt, sDtbTable, sDtbSize);
+2 -6
View File
@@ -86,12 +86,8 @@ fdt_set_kernel_args()
{ {
uint32_t fdtSize = fdt_totalsize(gFdt); uint32_t fdtSize = fdt_totalsize(gFdt);
// FDT needs to be 8-byte aligned for libfdt // libfdt requires 8-byte alignment
// TODO: We need kernel_args_malloc with alignment! gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(fdtSize, 8);
#define FDT_ALIGNMENT 8
#define FDT_ALIGN(addr) (((addr) + FDT_ALIGNMENT - 1) & ~(FDT_ALIGNMENT - 1))
gKernelArgs.arch_args.fdt
= (void*)FDT_ALIGN((addr_t)kernel_args_malloc(fdtSize + FDT_ALIGNMENT - 1));
if (gKernelArgs.arch_args.fdt != NULL) { if (gKernelArgs.arch_args.fdt != NULL) {
memcpy(gKernelArgs.arch_args.fdt, gFdt, fdtSize); memcpy(gKernelArgs.arch_args.fdt, gFdt, fdtSize);