/* Read a heartbeart info */ int vmfs_heartbeat_read(vmfs_heartbeat_t *hb,const u_char *buf) { hb->magic = read_le32(buf,VMFS_HB_OFS_MAGIC); hb->pos = read_le64(buf,VMFS_HB_OFS_POS); hb->seq = read_le64(buf,VMFS_HB_OFS_SEQ); hb->uptime = read_le64(buf,VMFS_HB_OFS_UPTIME); hb->journal_blk = read_le32(buf,VMFS_HB_OFS_JOURNAL_BLK); read_uuid(buf,VMFS_HB_OFS_UUID,&hb->uuid); return(0); }
/* Read volume information */ static int vmfs_volinfo_read(vmfs_volume_t *volume) { DECL_ALIGNED_BUFFER(buf,1024); vmfs_volinfo_t *vol = &volume->vol_info; if (m_pread(volume->fd,buf,buf_len,volume->vmfs_base) != buf_len) return(-1); vol->magic = read_le32(buf,VMFS_VOLINFO_OFS_MAGIC); if (vol->magic != VMFS_VOLINFO_MAGIC) { fprintf(stderr,"VMFS VolInfo: invalid magic number 0x%8.8x\n", vol->magic); return(-1); } vol->version = read_le32(buf,VMFS_VOLINFO_OFS_VER); vol->size = read_le32(buf,VMFS_VOLINFO_OFS_SIZE); vol->lun = buf[VMFS_VOLINFO_OFS_LUN]; vol->name = strndup((char *)buf+VMFS_VOLINFO_OFS_NAME, VMFS_VOLINFO_OFS_NAME_SIZE); read_uuid(buf,VMFS_VOLINFO_OFS_UUID,&vol->uuid); vol->lvm_size = read_le64(buf,VMFS_LVMINFO_OFS_SIZE); vol->blocks = read_le64(buf,VMFS_LVMINFO_OFS_BLKS); vol->num_segments = read_le32(buf,VMFS_LVMINFO_OFS_NUM_SEGMENTS); vol->first_segment = read_le32(buf,VMFS_LVMINFO_OFS_FIRST_SEGMENT); vol->last_segment = read_le32(buf,VMFS_LVMINFO_OFS_LAST_SEGMENT); vol->num_extents = read_le32(buf,VMFS_LVMINFO_OFS_NUM_EXTENTS); read_uuid(buf,VMFS_LVMINFO_OFS_UUID,&vol->lvm_uuid); #ifdef VMFS_CHECK { /* The LVM UUID also appears as a string, so we can check whether our formatting function is correct. */ char uuidstr1[M_UUID_BUFLEN], uuidstr2[M_UUID_BUFLEN]; memcpy(uuidstr1,buf+VMFS_LVMINFO_OFS_UUID_STR,M_UUID_BUFLEN-1); uuidstr1[M_UUID_BUFLEN-1] = 0; if (memcmp(m_uuid_to_str(vol->lvm_uuid,uuidstr2),uuidstr1, M_UUID_BUFLEN-1)) { fprintf(stderr, "uuid mismatch:\n%s\n%s\n",uuidstr1,uuidstr2); return(-1); } } #endif return(0); }
/* Read a metadata header */ int vmfs_metadata_hdr_read(vmfs_metadata_hdr_t *mdh,const u_char *buf) { mdh->magic = read_le32(buf,VMFS_MDH_OFS_MAGIC); mdh->pos = read_le64(buf,VMFS_MDH_OFS_POS); mdh->hb_pos = read_le64(buf,VMFS_MDH_OFS_HB_POS); mdh->hb_seq = read_le64(buf,VMFS_MDH_OFS_HB_SEQ); mdh->obj_seq = read_le64(buf,VMFS_MDH_OFS_OBJ_SEQ); mdh->hb_lock = read_le32(buf,VMFS_MDH_OFS_HB_LOCK); mdh->mtime = read_le64(buf,VMFS_MDH_OFS_MTIME); read_uuid(buf,VMFS_MDH_OFS_HB_UUID,&mdh->hb_uuid); return(0); }
void coreboot_table_setup(void *base) { cb_header_t *header = base; void *ptr; int i; if (strncmp(header->signature, "LBIO", 4)) { ERROR("coreboot table signature corrupt!\n"); return; } ptr = base + header->header_bytes; for (i = 0; i < header->table_entries; i++) { cb_entry_t *entry = ptr; if (ptr - base >= header->header_bytes + header->table_bytes) { ERROR("coreboot table exceeds its bounds!\n"); break; } switch (read_le32(&entry->tag)) { case CB_TAG_SERIAL: memcpy(&coreboot_serial, &entry->serial, sizeof(coreboot_serial)); break; case CB_TAG_CBMEM_CONSOLE: setup_cbmem_console(read_le64(&entry->uint64)); break; default: /* There are many tags TF doesn't need to care about. */ break; } ptr += read_le32(&entry->size); } }
static ssize_t relocate_fvh(uintptr_t new_addr, void *fsp, size_t fsp_size, size_t fvh_offset, size_t *fih_offset) { EFI_FIRMWARE_VOLUME_HEADER *fvh; EFI_FFS_FILE_HEADER *ffsfh; EFI_COMMON_SECTION_HEADER *csh; size_t offset; size_t file_offset; size_t size; size_t fv_length; offset = fvh_offset; fvh = relative_offset(fsp, offset); if (read_le32(&fvh->Signature) != EFI_FVH_SIGNATURE) return -1; fv_length = read_le64(&fvh->FvLength); printk(FSP_DBG_LVL, "FVH length: %zx Offset: %zx Mapping length: %zx\n", fv_length, offset, fsp_size); if (fv_length + offset > fsp_size) return -1; /* Parse only this FV. However, the algorithm uses offsets into the * entire FSP region so make size include the starting offset. */ size = fv_length + offset; if (guid_compare(&fvh->FileSystemGuid, &ffs2_guid)) { printk(BIOS_ERR, "FVH not an FFS2 type.\n"); return -1; } if (read_le16(&fvh->ExtHeaderOffset) != 0) { EFI_FIRMWARE_VOLUME_EXT_HEADER *fveh; offset += read_le16(&fvh->ExtHeaderOffset); fveh = relative_offset(fsp, offset); printk(FSP_DBG_LVL, "Extended Header Offset: %zx Size: %zx\n", (size_t)read_le16(&fvh->ExtHeaderOffset), (size_t)read_le32(&fveh->ExtHeaderSize)); offset += read_le32(&fveh->ExtHeaderSize); /* FFS files are 8 byte aligned after extended header. */ offset = ALIGN_UP(offset, 8); } else { offset += read_le16(&fvh->HeaderLength); } file_offset = offset; while (file_offset + sizeof(*ffsfh) < size) { offset = file_offset; printk(FSP_DBG_LVL, "file offset: %zx\n", file_offset); /* First file and section should be FSP info header. */ if (fih_offset != NULL && *fih_offset == 0) *fih_offset = file_offset; ffsfh = relative_offset(fsp, file_offset); printk(FSP_DBG_LVL, "file type = %x\n", read_le8(&ffsfh->Type)); printk(FSP_DBG_LVL, "file attribs = %x\n", read_le8(&ffsfh->Attributes)); /* Exit FV relocation when empty space found */ if (read_le8(&ffsfh->Type) == EFI_FV_FILETYPE_FFS_MAX) break; /* Next file on 8 byte alignment. */ file_offset += ffs_file_size(ffsfh); file_offset = ALIGN_UP(file_offset, 8); /* Padding files have no section information. */ if (read_le8(&ffsfh->Type) == EFI_FV_FILETYPE_FFS_PAD) continue; offset += file_section_offset(ffsfh); while (offset + sizeof(*csh) < file_offset) { size_t data_size; size_t data_offset; csh = relative_offset(fsp, offset); printk(FSP_DBG_LVL, "section offset: %zx\n", offset); printk(FSP_DBG_LVL, "section type: %x\n", read_le8(&csh->Type)); data_size = section_data_size(csh); data_offset = section_data_offset(csh); if (data_size + data_offset + offset > file_offset) { printk(BIOS_ERR, "Section exceeds FV size.\n"); return -1; } /* * The entire FSP 1.1 image can be thought of as one * program with a single link address even though there * are multiple TEs linked separately. The reason is * that each TE is linked for XIP. So in order to * relocate the TE properly we need to form the * relocated address based on the TE offset within * FSP proper. */ if (read_le8(&csh->Type) == EFI_SECTION_TE) { void *te; size_t te_offset = offset + data_offset; uintptr_t te_addr = new_addr + te_offset; printk(FSP_DBG_LVL, "TE image at offset %zx\n", te_offset); te = relative_offset(fsp, te_offset); te_relocate(te_addr, te); } offset += data_size + data_offset; /* Sections are aligned to 4 bytes. */ offset = ALIGN_UP(offset, 4); } } /* Return amount of buffer parsed: FV size. */ return fv_length; }
static int te_relocate(uintptr_t new_addr, void *te) { EFI_TE_IMAGE_HEADER *teih; EFI_IMAGE_DATA_DIRECTORY *relocd; EFI_IMAGE_BASE_RELOCATION *relocb; uintptr_t image_base; size_t fixup_offset; size_t num_relocs; uint16_t *reloc; size_t relocd_offset; uint8_t *te_base; uint32_t adj; teih = te; if (read_le16(&teih->Signature) != EFI_TE_IMAGE_HEADER_SIGNATURE) { printk(BIOS_ERR, "TE Signature mismatch: %x vs %x\n", read_le16(&teih->Signature), EFI_TE_IMAGE_HEADER_SIGNATURE); return -1; } /* * A TE image is created by converting a PE file. Because of this * the offsets within the headers are off. In order to calculate * the correct releative offets one needs to subtract fixup_offset * from the encoded offets. Similarly, the linked address of the * program is found by adding the fixup_offset to the ImageBase. */ fixup_offset = read_le16(&teih->StrippedSize); fixup_offset -= sizeof(EFI_TE_IMAGE_HEADER); /* Keep track of a base that is correctly adjusted so that offsets * can be used directly. */ te_base = te; te_base -= fixup_offset; image_base = read_le64(&teih->ImageBase); adj = new_addr - (image_base + fixup_offset); printk(FSP_DBG_LVL, "TE Image %p -> %p adjust value: %x\n", (void *)image_base, (void *)new_addr, adj); /* Adjust ImageBase for consistency. */ write_le64(&teih->ImageBase, (uint32_t)(image_base + adj)); relocd = &teih->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC]; relocd_offset = 0; /* Though the field name is VirtualAddress it's actually relative to * the beginning of the image which is linked at ImageBase. */ relocb = relative_offset(te, read_le32(&relocd->VirtualAddress) - fixup_offset); while (relocd_offset < read_le32(&relocd->Size)) { size_t rva_offset = read_le32(&relocb->VirtualAddress); printk(FSP_DBG_LVL, "Relocs for RVA offset %zx\n", rva_offset); num_relocs = read_le32(&relocb->SizeOfBlock) - sizeof(*relocb); num_relocs /= sizeof(uint16_t); reloc = relative_offset(relocb, sizeof(*relocb)); printk(FSP_DBG_LVL, "Num relocs in block: %zx\n", num_relocs); while (num_relocs > 0) { uint16_t reloc_val = read_le16(reloc); int type = reloc_type(reloc_val); size_t offset = reloc_offset(reloc_val); printk(FSP_DBG_LVL, "reloc type %x offset %zx\n", type, offset); if (type == EFI_IMAGE_REL_BASED_HIGHLOW) { uint32_t *reloc_addr; uint32_t val; offset += rva_offset; reloc_addr = (void *)&te_base[offset]; val = read_le32(reloc_addr); printk(FSP_DBG_LVL, "Adjusting %p %x -> %x\n", reloc_addr, val, val + adj); write_le32(reloc_addr, val + adj); } else if (type != EFI_IMAGE_REL_BASED_ABSOLUTE) { printk(BIOS_ERR, "Unknown reloc type: %x\n", type); return -1; } num_relocs--; reloc++; } /* Track consumption of relocation directory contents. */ relocd_offset += read_le32(&relocb->SizeOfBlock); /* Get next relocation block to process. */ relocb = relative_offset(relocb, read_le32(&relocb->SizeOfBlock)); } return 0; }
unsigned long fw_cfg_acpi_tables(unsigned long start) { BiosLinkerLoaderEntry *s; unsigned long *addrs, current; uint8_t *ptr; int rc, i, j, src, dst, max; rc = fw_cfg_check_file("etc/table-loader"); if (rc < 0) return 0; printk(BIOS_DEBUG, "QEMU: found ACPI tables in fw_cfg.\n"); max = rc / sizeof(*s); s = malloc(rc); addrs = malloc(max * sizeof(*addrs)); fw_cfg_load_file("etc/table-loader", s); current = start; for (i = 0; i < max && s[i].command != 0; i++) { void *cksum_data; uint32_t cksum; uint32_t addr4; uint64_t addr8; switch (s[i].command) { case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: current = ALIGN(current, s[i].alloc.align); rc = fw_cfg_check_file(s[i].alloc.file); if (rc < 0) goto err; printk(BIOS_DEBUG, "QEMU: loading \"%s\" to 0x%lx (len %d)\n", s[i].alloc.file, current, rc); fw_cfg_load_file(s[i].alloc.file, (void*)current); addrs[i] = current; current += rc; break; case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: src = -1; dst = -1; for (j = 0; j < i; j++) { if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE) continue; if (strcmp(s[j].alloc.file, s[i].pointer.dest_file) == 0) dst = j; if (strcmp(s[j].alloc.file, s[i].pointer.src_file) == 0) src = j; } if (src == -1 || dst == -1) goto err; switch (s[i].pointer.size) { case 4: ptr = (uint8_t *)addrs[dst]; ptr += s[i].pointer.offset; addr4 = read_le32(ptr); addr4 += addrs[src]; write_le32(ptr, addr4); break; case 8: ptr = (uint8_t *)addrs[dst]; ptr += s[i].pointer.offset; addr8 = read_le64(ptr); addr8 += addrs[src]; write_le64(ptr, addr8); break; default: /* * Should not happen. ACPI knows 1 and 2 byte ptrs * too, but we are operating with 32bit offsets which * would simply not fit in there ... */ printk(BIOS_DEBUG, "QEMU: acpi: unimplemented ptr size %d\n", s[i].pointer.size); goto err; } break; case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: dst = -1; for (j = 0; j < i; j++) { if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE) continue; if (strcmp(s[j].alloc.file, s[i].cksum.file) == 0) dst = j; } if (dst == -1) goto err; ptr = (uint8_t *)(addrs[dst] + s[i].cksum.offset); cksum_data = (void *)(addrs[dst] + s[i].cksum.start); cksum = acpi_checksum(cksum_data, s[i].cksum.length); write_le8(ptr, cksum); break; default: printk(BIOS_DEBUG, "QEMU: acpi: unknown script cmd 0x%x @ %p\n", s[i].command, s+i); goto err; }; } printk(BIOS_DEBUG, "QEMU: loaded ACPI tables from fw_cfg.\n"); free(s); free(addrs); return ALIGN(current, 16); err: printk(BIOS_DEBUG, "QEMU: loading ACPI tables from fw_cfg failed.\n"); free(s); free(addrs); return 0; }