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" {
|
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 */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user