status_t add_safe_mode_settings(char* settings) { if (settings == NULL || settings[0] == '\0') return B_OK; size_t length = strlen(settings); char* buffer = (char*)kernel_args_malloc(length + 1); if (buffer == NULL) return B_NO_MEMORY; driver_settings_file* file = (driver_settings_file*)kernel_args_malloc( sizeof(driver_settings_file)); if (file == NULL) { kernel_args_free(buffer); return B_NO_MEMORY; } strlcpy(file->name, B_SAFEMODE_DRIVER_SETTINGS, sizeof(file->name)); memcpy(buffer, settings, length + 1); file->buffer = buffer; file->size = length; // add it to the list file->next = gKernelArgs.driver_settings; gKernelArgs.driver_settings = file; return B_OK; }
extern "C" void platform_start_kernel(void) { preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>( gKernelArgs.kernel_image.Pointer()); addr_t kernelEntry = image->elf_header.e_entry; addr_t stackTop = gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size; // clone the Flattened Device Tree blob into the kernel args if we've got it if (gFDT) { size_t fdtSize = fdt_totalsize(gFDT); gKernelArgs.platform_args.fdt = kernel_args_malloc(fdtSize); memcpy(gKernelArgs.platform_args.fdt, gFDT, fdtSize); } // smp_init_other_cpus(); serial_cleanup(); mmu_init_for_kernel(); // smp_boot_other_cpus(); dprintf("kernel entry at %lx\n", kernelEntry); status_t error = arch_start_kernel(&gKernelArgs, kernelEntry, stackTop); panic("kernel returned %lx!\n", error); }
/*static*/ status_t ELFLoader<Class>::Create(int fd, preloaded_image** _image) { ImageType* image = (ImageType*)kernel_args_malloc(sizeof(ImageType)); if (image == NULL) return B_NO_MEMORY; ssize_t length = read_pos(fd, 0, &image->elf_header, sizeof(EhdrType)); if (length < (ssize_t)sizeof(EhdrType)) { kernel_args_free(image); return B_BAD_TYPE; } const EhdrType& elfHeader = image->elf_header; if (memcmp(elfHeader.e_ident, ELF_MAGIC, 4) != 0 || elfHeader.e_ident[4] != Class::kIdentClass || elfHeader.e_phoff == 0 || !elfHeader.IsHostEndian() || elfHeader.e_phentsize != sizeof(PhdrType)) { kernel_args_free(image); return B_BAD_TYPE; } image->elf_class = elfHeader.e_ident[EI_CLASS]; *_image = image; return B_OK; }
extern "C" void serial_cleanup(void) { if (sSerialEnabled <= 0) return; gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition); if (gKernelArgs.debug_output != NULL) { memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition); gKernelArgs.debug_size = sBufferPosition; } }
static status_t load_driver_settings_file(Directory* directory, const char* name) { int fd = open_from(directory, name, O_RDONLY); if (fd < 0) return fd; struct stat stat; if (fstat(fd, &stat) < 0) return errno; char* buffer = (char*)kernel_args_malloc(stat.st_size + 1); if (buffer == NULL) return B_NO_MEMORY; if (read(fd, buffer, stat.st_size) != stat.st_size) return B_IO_ERROR; driver_settings_file* file = (driver_settings_file*)kernel_args_malloc( sizeof(driver_settings_file)); if (file == NULL) { kernel_args_free(buffer); return B_NO_MEMORY; } buffer[stat.st_size] = '\0'; // null terminate the buffer strlcpy(file->name, name, sizeof(file->name)); file->buffer = buffer; file->size = stat.st_size; // add it to the list file->next = gKernelArgs.driver_settings; gKernelArgs.driver_settings = file; return B_OK; }
/*! Convenience function that copies strdup() functions for the kernel args heap. */ extern "C" char * kernel_args_strdup(const char *string) { if (string == NULL || string[0] == '\0') return NULL; size_t length = strlen(string) + 1; char *target = (char *)kernel_args_malloc(length); if (target == NULL) return NULL; memcpy(target, string, length); return target; }
status_t elf_load_image(Directory *directory, const char *path) { preloaded_image *image; TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path)); int fd = open_from(directory, path, O_RDONLY); if (fd < 0) return fd; // check if this file has already been loaded struct stat stat; if (fstat(fd, &stat) < 0) return errno; image = gKernelArgs.preloaded_images; for (; image != NULL; image = image->next) { if (image->inode == stat.st_ino) { // file has already been loaded, no need to load it twice! close(fd); return B_OK; } } // we still need to load it, so do it image = (preloaded_image *)kernel_args_malloc(sizeof(preloaded_image)); if (image == NULL) { close(fd); return B_NO_MEMORY; } status_t status = elf_load_image(fd, image); if (status == B_OK) { image->name = kernel_args_strdup(path); image->inode = stat.st_ino; // insert to kernel args image->next = gKernelArgs.preloaded_images; gKernelArgs.preloaded_images = image; } else kernel_args_free(image); close(fd); return status; }
/*static*/ status_t ELFLoader<Class>::_LoadSymbolTable(int fd, ImageType* image) { const EhdrType& elfHeader = image->elf_header; SymType* symbolTable = NULL; ShdrType* stringHeader = NULL; uint32 numSymbols = 0; char* stringTable; status_t status; // get section headers ssize_t size = elfHeader.e_shnum * elfHeader.e_shentsize; ShdrType* sectionHeaders = (ShdrType*)malloc(size); if (sectionHeaders == NULL) { dprintf("error allocating space for section headers\n"); return B_NO_MEMORY; } ssize_t length = read_pos(fd, elfHeader.e_shoff, sectionHeaders, size); if (length < size) { TRACE(("error reading in program headers\n")); status = B_ERROR; goto error1; } // find symbol table in section headers for (int32 i = 0; i < elfHeader.e_shnum; i++) { if (sectionHeaders[i].sh_type == SHT_SYMTAB) { stringHeader = §ionHeaders[sectionHeaders[i].sh_link]; if (stringHeader->sh_type != SHT_STRTAB) { TRACE(("doesn't link to string table\n")); status = B_BAD_DATA; goto error1; } // read in symbol table size = sectionHeaders[i].sh_size; symbolTable = (SymType*)kernel_args_malloc(size); if (symbolTable == NULL) { status = B_NO_MEMORY; goto error1; } length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable, size); if (length < size) { TRACE(("error reading in symbol table\n")); status = B_ERROR; goto error1; } numSymbols = size / sizeof(SymType); break; } } if (symbolTable == NULL) { TRACE(("no symbol table\n")); status = B_BAD_VALUE; goto error1; } // read in string table size = stringHeader->sh_size; stringTable = (char*)kernel_args_malloc(size); if (stringTable == NULL) { status = B_NO_MEMORY; goto error2; } length = read_pos(fd, stringHeader->sh_offset, stringTable, size); if (length < size) { TRACE(("error reading in string table\n")); status = B_ERROR; goto error3; } TRACE(("loaded %ld debug symbols\n", numSymbols)); // insert tables into image image->debug_symbols = symbolTable; image->num_debug_symbols = numSymbols; image->debug_string_table = stringTable; image->debug_string_table_size = size; free(sectionHeaders); return B_OK; error3: kernel_args_free(stringTable); error2: kernel_args_free(symbolTable); error1: free(sectionHeaders); return status; }
extern "C" int main(stage2_args *args) { TRACE(("boot(): enter\n")); if (heap_init(args) < B_OK) panic("Could not initialize heap!\n"); TRACE(("boot(): heap initialized...\n")); // set debug syslog default #if KDEBUG_ENABLE_DEBUG_SYSLOG gKernelArgs.keep_debug_output_buffer = true; #endif add_stage2_driver_settings(args); platform_init_video(); // the main platform dependent initialisation // has already taken place at this point. if (vfs_init(args) < B_OK) panic("Could not initialize VFS!\n"); dprintf("Welcome to the Haiku boot loader!\n"); bool mountedAllVolumes = false; Directory *volume = get_boot_file_system(args); if (volume == NULL || (platform_boot_options() & BOOT_OPTION_MENU) != 0) { if (volume == NULL) puts("\tno boot path found, scan for all partitions...\n"); if (mount_file_systems(args) < B_OK) { // That's unfortunate, but we still give the user the possibility // to insert a CD-ROM or just rescan the available devices puts("Could not locate any supported boot devices!\n"); } // ToDo: check if there is only one bootable volume! mountedAllVolumes = true; if (user_menu(&volume) < B_OK) { // user requested to quit the loader goto out; } } if (volume != NULL) { // we got a volume to boot from! status_t status; while ((status = load_kernel(args, volume)) < B_OK) { // loading the kernel failed, so let the user choose another // volume to boot from until it works volume = NULL; if (!mountedAllVolumes) { // mount all other file systems, if not already happened if (mount_file_systems(args) < B_OK) panic("Could not locate any supported boot devices!\n"); mountedAllVolumes = true; } if (user_menu(&volume) < B_OK || volume == NULL) { // user requested to quit the loader goto out; } } // if everything is okay, continue booting; the kernel // is already loaded at this point and we definitely // know our boot volume, too if (status == B_OK) { register_boot_file_system(volume); if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0) platform_switch_to_logo(); load_modules(args, volume); load_driver_settings(args, volume); // apply boot settings apply_boot_settings(); // set up kernel args version info gKernelArgs.kernel_args_size = sizeof(kernel_args); gKernelArgs.version = CURRENT_KERNEL_ARGS_VERSION; // clone the boot_volume KMessage into kernel accessible memory // note, that we need to 4 byte align the buffer and thus allocate // 3 more bytes void* buffer = kernel_args_malloc(gBootVolume.ContentSize() + 3); if (!buffer) { panic("Could not allocate memory for the boot volume kernel " "arguments"); } buffer = (void*)(((addr_t)buffer + 3) & ~(addr_t)0x3); memcpy(buffer, gBootVolume.Buffer(), gBootVolume.ContentSize()); gKernelArgs.boot_volume = buffer; gKernelArgs.boot_volume_size = gBootVolume.ContentSize(); // ToDo: cleanup, heap_release() etc. platform_start_kernel(); } } out: heap_release(args); return 0; }
extern "C" status_t video_display_splash(addr_t frameBuffer) { if (!gKernelArgs.frame_buffer.enabled) return B_NO_INIT; // clear the video memory memset((void*)frameBuffer, 0, gKernelArgs.frame_buffer.physical_buffer.size); uint8* uncompressedLogo = NULL; unsigned int uncompressedSize = kSplashLogoWidth * kSplashLogoHeight; switch (gKernelArgs.frame_buffer.depth) { case 8: platform_set_palette(k8BitPalette); uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize); if (uncompressedLogo == NULL) return B_NO_MEMORY; uncompress(kSplashLogo8BitCompressedImage, sizeof(kSplashLogo8BitCompressedImage), uncompressedLogo, uncompressedSize); break; default: // 24 bits is assumed here uncompressedSize *= 3; uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize); if (uncompressedLogo == NULL) return B_NO_MEMORY; uncompress(kSplashLogo24BitCompressedImage, sizeof(kSplashLogo24BitCompressedImage), uncompressedLogo, uncompressedSize); break; } // TODO: support 4-bit indexed version of the images! // render splash logo uint16 iconsHalfHeight = kSplashIconsHeight / 2; int width = min_c(kSplashLogoWidth, gKernelArgs.frame_buffer.width); int height = min_c(kSplashLogoHeight + iconsHalfHeight, gKernelArgs.frame_buffer.height); int placementX = max_c(0, min_c(100, kSplashLogoPlacementX)); int placementY = max_c(0, min_c(100, kSplashLogoPlacementY)); int x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100; height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height); switch (gKernelArgs.frame_buffer.depth) { case 8: break; } video_blit_image(frameBuffer, uncompressedLogo, width, height, kSplashLogoWidth, x, y); kernel_args_free(uncompressedLogo); const uint8* lowerHalfIconImage; uncompressedSize = kSplashIconsWidth * kSplashIconsHeight; switch (gKernelArgs.frame_buffer.depth) { case 8: // pointer into the lower half of the icons image data gKernelArgs.boot_splash = (uint8*)kernel_args_malloc(uncompressedSize); if (gKernelArgs.boot_splash == NULL) return B_NO_MEMORY; uncompress(kSplashIcons8BitCompressedImage, sizeof(kSplashIcons8BitCompressedImage), gKernelArgs.boot_splash, uncompressedSize); lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash + (kSplashIconsWidth * iconsHalfHeight); break; default: // 24bits is assumed here uncompressedSize *= 3; // pointer into the lower half of the icons image data gKernelArgs.boot_splash = (uint8*)kernel_args_malloc(uncompressedSize); if (gKernelArgs.boot_splash == NULL) return B_NO_MEMORY; uncompress(kSplashIcons24BitCompressedImage, sizeof(kSplashIcons24BitCompressedImage), gKernelArgs.boot_splash, uncompressedSize); lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash + (kSplashIconsWidth * iconsHalfHeight) * 3; break; } // render initial (grayed out) icons // the grayed out version is the lower half of the icons image width = min_c(kSplashIconsWidth, gKernelArgs.frame_buffer.width); height = min_c(kSplashLogoHeight + iconsHalfHeight, gKernelArgs.frame_buffer.height); placementX = max_c(0, min_c(100, kSplashIconsPlacementX)); placementY = max_c(0, min_c(100, kSplashIconsPlacementY)); x = (gKernelArgs.frame_buffer.width - width) * placementX / 100; y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height) * placementY / 100; height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height); video_blit_image(frameBuffer, lowerHalfIconImage, width, height, kSplashIconsWidth, x, y); return B_OK; }