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:
committed by
Adrien Destugues
parent
c9d6d52b03
commit
4b5c7fe7e1
@@ -19,14 +19,14 @@ extern KMessage gBootVolume;
|
||||
extern "C" {
|
||||
#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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#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 */
|
||||
|
||||
@@ -350,11 +350,10 @@ ucode_load(BootVolume& volume)
|
||||
}
|
||||
|
||||
ssize_t length = stat.st_size;
|
||||
const uint32 alignment = 16;
|
||||
#define ALIGN(size, align) (((size) + align - 1) & ~(align - 1))
|
||||
void *buffer = kernel_args_malloc(length + alignment - 1);
|
||||
|
||||
// 16-byte alignment required
|
||||
void *buffer = kernel_args_malloc(length, 16);
|
||||
if (buffer != NULL) {
|
||||
buffer = (void*)ALIGN((addr_t)buffer, alignment);
|
||||
if (read(fd, buffer, length) != length) {
|
||||
dprintf("ucode_load: couldn't read microcode file\n");
|
||||
kernel_args_free(buffer);
|
||||
|
||||
@@ -369,68 +369,10 @@ ignore_physical_memory_ranges_beyond_4gb()
|
||||
// #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
|
||||
kernel args heap.
|
||||
*/
|
||||
extern "C" char*
|
||||
char*
|
||||
kernel_args_strdup(const char* string)
|
||||
{
|
||||
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().
|
||||
It's very simple; it can only free the last allocation. It's
|
||||
enough for its current usage in the boot loader, though.
|
||||
*/
|
||||
extern "C" void
|
||||
void
|
||||
kernel_args_free(void* block)
|
||||
{
|
||||
if (sLast != block) {
|
||||
|
||||
@@ -464,13 +464,8 @@ dtb_set_kernel_args()
|
||||
if (sDtbTable != NULL) {
|
||||
#if defined(__ARM__) || defined(__riscv)
|
||||
|
||||
// FDT needs to be 8-byte aligned for libfdt
|
||||
// TODO: we need kernel_args_malloc with alignment!
|
||||
#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));
|
||||
// libfdt requires 8-byte alignment
|
||||
gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(sDtbSize, 8);
|
||||
|
||||
if (gKernelArgs.arch_args.fdt != NULL)
|
||||
memcpy(gKernelArgs.arch_args.fdt, sDtbTable, sDtbSize);
|
||||
|
||||
@@ -86,12 +86,8 @@ fdt_set_kernel_args()
|
||||
{
|
||||
uint32_t fdtSize = fdt_totalsize(gFdt);
|
||||
|
||||
// FDT needs to be 8-byte aligned for libfdt
|
||||
// TODO: We need kernel_args_malloc with alignment!
|
||||
#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));
|
||||
// libfdt requires 8-byte alignment
|
||||
gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(fdtSize, 8);
|
||||
|
||||
if (gKernelArgs.arch_args.fdt != NULL) {
|
||||
memcpy(gKernelArgs.arch_args.fdt, gFdt, fdtSize);
|
||||
|
||||
Reference in New Issue
Block a user