Example #1
0
/* Write a heartbeat info */
int vmfs_heartbeat_write(const vmfs_heartbeat_t *hb,u_char *buf)
{
   write_le32(buf,VMFS_HB_OFS_MAGIC,hb->magic);
   write_le64(buf,VMFS_HB_OFS_POS,hb->pos);
   write_le64(buf,VMFS_HB_OFS_SEQ,hb->seq);
   write_le64(buf,VMFS_HB_OFS_UPTIME,hb->uptime);
   write_le32(buf,VMFS_HB_OFS_JOURNAL_BLK,hb->journal_blk);
   write_uuid(buf,VMFS_HB_OFS_UUID,&hb->uuid);
   return(0);
}
Example #2
0
/* Write a metadata header */
int vmfs_metadata_hdr_write(const vmfs_metadata_hdr_t *mdh,u_char *buf)
{
   memset(buf,0,VMFS_METADATA_HDR_SIZE);
   write_le32(buf,VMFS_MDH_OFS_MAGIC,mdh->magic);
   write_le64(buf,VMFS_MDH_OFS_POS,mdh->pos);
   write_le64(buf,VMFS_MDH_OFS_HB_POS,mdh->hb_pos);
   write_le64(buf,VMFS_MDH_OFS_HB_SEQ,mdh->hb_seq);
   write_le64(buf,VMFS_MDH_OFS_OBJ_SEQ,mdh->obj_seq);
   write_le32(buf,VMFS_MDH_OFS_HB_LOCK,mdh->hb_lock);
   write_le64(buf,VMFS_MDH_OFS_MTIME,mdh->mtime);
   write_uuid(buf,VMFS_MDH_OFS_HB_UUID,&mdh->hb_uuid);
   return(0);
}
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;
}
Example #4
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;
}
Example #5
0
static int cmd_remove(vmfs_fs_t *fs,int argc,char *argv[])
{
   /* Dangerous */
   vmfs_lvm_t *lvm = (vmfs_lvm_t *)fs->dev;
   vmfs_volume_t *extent;
   DECL_ALIGNED_BUFFER(buf,512);
   vmfs_bitmap_entry_t entry;
   uint32_t i, blocks_per_segment, items_per_area,
            items_in_last_entry, old_area_count;

   fprintf(stderr, "Extents removal is experimental ! Use at your own risk !\n");
   while (1) {
      char *answer = local_readline("Are you sure you want to go further? [y/N] ");
      char a = answer[0];
      char null = answer[1];
      free(answer);
      if ((a == 0) || ((tolower(a) == 'n') && (null == 0)))
         return(2);
      if ((tolower(a) == 'y') && (null == 0))
         break;
   }
   if (lvm->lvm_info.num_extents == 1) {
      fprintf(stderr, "Can't remove an extent when there is only one\n");
      return(1);
   }

   /* Get last extent */
   extent = lvm->extents[lvm->loaded_extents - 1];

   /* Check whether data blocks are used on the last extents */
   blocks_per_segment = VMFS_LVM_SEGMENT_SIZE / vmfs_fs_get_blocksize(fs);
   for (i = extent->vol_info.first_segment * blocks_per_segment;
        i < extent->vol_info.last_segment * blocks_per_segment;
        i++)
      if (vmfs_block_get_status(fs, VMFS_BLK_FB_BUILD(i, 0))) {
         fprintf(stderr, "There is data on the last extent ; can't remove it\n");
         return(1);
      }

   /* At filesystem level, only the FBB needs to be downsized */
   fs->fbb->bmh.total_items -= extent->vol_info.num_segments * blocks_per_segment;
   items_per_area = fs->fbb->bmh.items_per_bitmap_entry *
                    fs->fbb->bmh.bmp_entries_per_area;
   old_area_count = fs->fbb->bmh.area_count;
   fs->fbb->bmh.area_count = (fs->fbb->bmh.total_items + items_per_area - 1) /
                             items_per_area;

   memset(buf, 0, buf_len);
   vmfs_bmh_write(&fs->fbb->bmh, buf);
   /* TODO: Error handling */
   vmfs_file_pwrite(fs->fbb->f, buf, buf_len, 0);

   /* Adjust new last entry */
   if ((items_in_last_entry =
        fs->fbb->bmh.total_items % fs->fbb->bmh.items_per_bitmap_entry)) {
      vmfs_bitmap_get_entry(fs->fbb, 0, fs->fbb->bmh.total_items, &entry);
      entry.free -= entry.total - items_in_last_entry;
      entry.total = items_in_last_entry;
      if (entry.ffree > entry.total)
         entry.ffree = 0;
      /* Adjust bitmap in last entry */
      if (items_in_last_entry % 8)
         entry.bitmap[items_in_last_entry / 8] &=
            0xff << (8 - (items_in_last_entry % 8));
      memset(&entry.bitmap[(items_in_last_entry + 7) / 8], 0,
         (fs->fbb->bmh.items_per_bitmap_entry - items_in_last_entry - 7) / 8);
      vmfs_bme_update(fs, &entry);
   }
   /* Truncate the fbb file depending on the new area count */
   if (old_area_count != fs->fbb->bmh.area_count)
      vmfs_file_truncate(fs->fbb->f, fs->fbb->bmh.hdr_size +
                            fs->fbb->bmh.area_count * fs->fbb->bmh.area_size);
   /* Adjust entries after the new last one */
   for (i = fs->fbb->bmh.total_items + (items_in_last_entry ?
           (fs->fbb->bmh.items_per_bitmap_entry - items_in_last_entry) : 0);
        i < fs->fbb->bmh.area_count * items_per_area;
        i += fs->fbb->bmh.items_per_bitmap_entry) {
      uint64_t pos;
      vmfs_bitmap_get_entry(fs->fbb, 0, i, &entry);
      pos = entry.mdh.pos;
      memset(&entry, 0, sizeof(entry));
      vmfs_device_write(fs->dev, pos, (u_char *)&entry, sizeof(entry));
   }

   /* At LVM level, all extents need to have the LVM information updated */
   for (i = 0; i < lvm->loaded_extents - 1; i++) {
      lvm->extents[i]->vol_info.blocks -= extent->vol_info.num_segments + 1;
      lvm->extents[i]->vol_info.num_extents--;
      lvm->extents[i]->vol_info.lvm_size =
         (lvm->extents[i]->vol_info.blocks -
            lvm->extents[i]->vol_info.num_extents) * VMFS_LVM_SEGMENT_SIZE;

      /* Until there is an API for that, do it by hand */
      m_pread(lvm->extents[i]->fd,buf,buf_len,
              lvm->extents[i]->vmfs_base + VMFS_LVMINFO_OFFSET);
      write_le64(buf, VMFS_LVMINFO_OFS_SIZE - VMFS_LVMINFO_OFFSET,
         lvm->extents[i]->vol_info.lvm_size);
      write_le64(buf, VMFS_LVMINFO_OFS_BLKS - VMFS_LVMINFO_OFFSET,
         lvm->extents[i]->vol_info.blocks);
      write_le32(buf, VMFS_LVMINFO_OFS_NUM_EXTENTS - VMFS_LVMINFO_OFFSET,
         lvm->extents[i]->vol_info.num_extents);
      m_pwrite(lvm->extents[i]->fd,buf,buf_len,
               lvm->extents[i]->vmfs_base + VMFS_LVMINFO_OFFSET);
   }
   return(0);
}