--- zzzz-none-000/linux-5.15.111/drivers/firmware/efi/libstub/file.c 2023-05-11 14:00:40.000000000 +0000 +++ puma7-atom-6670-761/linux-5.15.111/drivers/firmware/efi/libstub/file.c 2024-02-07 10:22:41.000000000 +0000 @@ -37,7 +37,8 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume, struct finfo *fi, efi_file_protocol_t **handle, - unsigned long *file_size) + unsigned long *file_size, + bool silent) { efi_guid_t info_guid = EFI_FILE_INFO_ID; efi_file_protocol_t *fh; @@ -46,14 +47,16 @@ status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0); if (status != EFI_SUCCESS) { - efi_err("Failed to open file: %ls\n", fi->filename); + if (!silent) + efi_err("Failed to open file: %ls\n", fi->filename); return status; } info_sz = sizeof(struct finfo); status = fh->get_info(fh, &info_guid, &info_sz, fi); if (status != EFI_SUCCESS) { - efi_err("Failed to get file info\n"); + if (!silent) + efi_err("Failed to get file info\n"); fh->close(fh); return status; } @@ -176,7 +179,7 @@ return status; } - status = efi_open_file(volume, &fi, &file, &size); + status = efi_open_file(volume, &fi, &file, &size, false); if (status != EFI_SUCCESS) goto err_close_volume; @@ -248,3 +251,126 @@ efi_free(alloc_size, alloc_addr); return status; } + +static efi_status_t avm_build_dtb_name_for(int hwrev, int hwsubrev, + efi_char16_t *path, size_t size) +{ + char apath[40]; + int len; + + len = snprintf(apath, sizeof(apath), "efi\\boot\\Fritz_Box_HW%u-%u.dtb", + hwrev, hwsubrev); + + if (len >= min(size, sizeof(apath))) + return EFI_BUFFER_TOO_SMALL; + + for (; len >= 0; --len) + path[len] = apath[len]; + + return EFI_SUCCESS; +} + +/* + * Check the efi/boot folder for a suitable DTB and load it. + * + * If no DTB filename matches the HW-Subrevision, it will look up DTBs for + * older subrevisions. If none is found, the function fails. + */ +efi_status_t avm_get_dtb_setup_data(efi_loaded_image_t *image, + struct setup_data **dtb_setup_data) +{ + unsigned long dtb_size, size, efi_varsiz; + efi_file_protocol_t *volume, *dtb_file; + struct setup_data *setup_data; + efi_status_t status; + int hwrev, hwsubrev; + struct finfo fi; + u8 efi_var[16]; + ssize_t len; + __u8 *data; + + if (!dtb_setup_data) + return EFI_INVALID_PARAMETER; + + efi_varsiz = sizeof(efi_var) - 1; + status = get_efi_var(L"HWRevision", &EFI_AVM_VARIABLE_GUID, NULL, + &efi_varsiz, efi_var); + if (status != EFI_SUCCESS) { + efi_err("Error reading EFI variable: %d\n", status); + return status; + } + + efi_var[efi_varsiz] = '\0'; + hwrev = simple_strtol(efi_var, NULL, 10); + + efi_varsiz = sizeof(efi_var) - 1; + status = get_efi_var(L"HWSubRevision", &EFI_AVM_VARIABLE_GUID, NULL, + &efi_varsiz, efi_var); + if (status != EFI_SUCCESS) + return status; + + efi_var[efi_varsiz] = '\0'; + hwsubrev = simple_strtol(efi_var, NULL, 10); + + status = efi_open_volume(image, &volume); + if (status != EFI_SUCCESS) + return status; + + for (;;) { + status = avm_build_dtb_name_for(hwrev, hwsubrev, fi.filename, + ARRAY_SIZE(fi.filename)); + if (status != EFI_SUCCESS) + return status; + + status = efi_open_file(volume, &fi, &dtb_file, &dtb_size, true); + if (status == EFI_SUCCESS) + break; + + if (hwsubrev-- == 0) { + efi_puts("No DTB found\n"); + return EFI_NOT_FOUND; + } + } + + efi_puts("DTB found: "); + efi_char16_puts(fi.filename); + efi_puts("\n"); + + status = efi_allocate_pages(dtb_size + sizeof(struct setup_data), + (unsigned long *)&setup_data, ULONG_MAX); + if (status != EFI_SUCCESS) { + efi_err("Failed to alloc pages for setup_data: %d\n", status); + goto close_dtb_file; + } + + data = setup_data->data; + size = dtb_size; + while (size) { + unsigned long chunksize = ULONG_MAX; + + if (IS_ENABLED(CONFIG_X86) && !efi_nochunk) + chunksize = EFI_READ_CHUNK_SIZE; + + status = dtb_file->read(dtb_file, &chunksize, data); + if (status != EFI_SUCCESS) { + efi_err("Failed to read dtb file: %d\n", status); + goto free_setup_data; + } + data += chunksize; + size -= chunksize; + } + + dtb_file->close(dtb_file); + + setup_data->type = SETUP_DTB; + setup_data->len = (__u32)dtb_size; + *dtb_setup_data = setup_data; + + return status; + +free_setup_data: + efi_free(dtb_size + sizeof(struct setup_data), (unsigned long)setup_data); +close_dtb_file: + dtb_file->close(dtb_file); + return status; +}