| 5 | namespace aarch64 { |
| 6 | |
| 7 | GPA LoadLinuxImage(BootConfig& config) { |
| 8 | FILE* fp = fopen(config.kernel_path.c_str(), "rb"); |
| 9 | if (!fp) { |
| 10 | LOG_ERROR("aarch64: cannot open kernel: %s", config.kernel_path.c_str()); |
| 11 | return 0; |
| 12 | } |
| 13 | |
| 14 | fseek(fp, 0, SEEK_END); |
| 15 | long file_size = ftell(fp); |
| 16 | fseek(fp, 0, SEEK_SET); |
| 17 | |
| 18 | if (file_size < static_cast<long>(sizeof(LinuxImageHeader))) { |
| 19 | LOG_ERROR("aarch64: kernel too small (%ld bytes)", file_size); |
| 20 | fclose(fp); |
| 21 | return 0; |
| 22 | } |
| 23 | |
| 24 | // Read and validate the ARM64 Image header |
| 25 | LinuxImageHeader hdr{}; |
| 26 | fread(&hdr, sizeof(hdr), 1, fp); |
| 27 | |
| 28 | if (hdr.magic != kArmImageMagic) { |
| 29 | LOG_ERROR("aarch64: invalid ARM64 Image magic (got 0x%08x, expected 0x%08x)", |
| 30 | hdr.magic, kArmImageMagic); |
| 31 | fclose(fp); |
| 32 | return 0; |
| 33 | } |
| 34 | |
| 35 | uint64_t text_offset = hdr.text_offset; |
| 36 | if (text_offset == 0) { |
| 37 | text_offset = 0x200000; // default 2 MiB offset |
| 38 | } |
| 39 | |
| 40 | GPA kernel_gpa = Layout::kRamBase + text_offset; |
| 41 | |
| 42 | // Validate kernel fits in guest RAM |
| 43 | uint64_t kernel_end_offset = text_offset + static_cast<uint64_t>(file_size); |
| 44 | if (kernel_end_offset > config.mem.alloc_size) { |
| 45 | LOG_ERROR("aarch64: kernel too large for guest RAM (%ld bytes)", file_size); |
| 46 | fclose(fp); |
| 47 | return 0; |
| 48 | } |
| 49 | |
| 50 | // Load kernel at the computed offset within guest RAM |
| 51 | // config.mem.base points to the host memory mapped at Layout::kRamBase |
| 52 | uint8_t* dest = config.mem.base + text_offset; |
| 53 | fseek(fp, 0, SEEK_SET); |
| 54 | size_t read = fread(dest, 1, static_cast<size_t>(file_size), fp); |
| 55 | fclose(fp); |
| 56 | |
| 57 | if (read != static_cast<size_t>(file_size)) { |
| 58 | LOG_ERROR("aarch64: short kernel read (%zu / %ld)", read, file_size); |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | LOG_INFO("aarch64: kernel loaded at GPA 0x%" PRIx64 " (%ld bytes, text_offset=0x%" PRIx64 ")", |
| 63 | (uint64_t)kernel_gpa, file_size, text_offset); |
| 64 | |