Exemple #1
0
static caddr_t
smbios_sigsearch(const caddr_t addr, const uint32_t len)
{
	caddr_t         cp;
	
	/* Search on 16-byte boundaries. */
	for (cp = addr; cp < addr + len; cp += SMBIOS_STEP)
		if (strncmp(cp, SMBIOS_SIG, 4) == 0 &&
			smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 &&
			strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5) == 0 &&
			smbios_checksum(cp + 0x10, 0x0f) == 0)
			return (cp);
	return (NULL);
}
Exemple #2
0
unsigned long smbios_write_tables(unsigned long current)
{
	struct smbios_entry *se;
	unsigned long tables;
	int len = 0;
	int max_struct_size = 0;
	int handle = 0;

	current = ALIGN(current, 16);
	printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current);

	se = (struct smbios_entry *)current;
	current += sizeof(struct smbios_entry);
	current = ALIGN(current, 16);

	tables = current;
	update_max(len, max_struct_size, smbios_write_type0(&current, handle++));
	update_max(len, max_struct_size, smbios_write_type1(&current, handle++));
	update_max(len, max_struct_size, smbios_write_type2(&current, handle++));
	update_max(len, max_struct_size, smbios_write_type3(&current, handle++));
	update_max(len, max_struct_size, smbios_write_type4(&current, handle++));
	update_max(len, max_struct_size, smbios_write_type11(&current, &handle));
#if CONFIG_ELOG
	update_max(len, max_struct_size, elog_smbios_write_type15(&current, handle++));
#endif
	update_max(len, max_struct_size, smbios_write_type17(&current, &handle));
	update_max(len, max_struct_size, smbios_write_type32(&current, handle++));

	update_max(len, max_struct_size, smbios_walk_device_tree(all_devices, &handle, &current));

	update_max(len, max_struct_size, smbios_write_type127(&current, handle++));

	memset(se, 0, sizeof(struct smbios_entry));
	memcpy(se->anchor, "_SM_", 4);
	se->length = sizeof(struct smbios_entry);
	se->major_version = 2;
	se->minor_version = 7;
	se->max_struct_size = max_struct_size;
	se->struct_count = handle;
	memcpy(se->intermediate_anchor_string, "_DMI_", 5);

	se->struct_table_address = (u32)tables;
	se->struct_table_length = len;

	se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10,
						    sizeof(struct smbios_entry) - 0x10);
	se->checksum = smbios_checksum((u8 *)se, sizeof(struct smbios_entry));
	return current;
}
Exemple #3
0
/*
 * Common code to copy out the SMBIOS snapshot used for both read and mmap.
 * The caller must validate uio_offset for us since semantics differ there.
 * The copy is done in two stages, either of which can be skipped based on the
 * offset and length: first we copy the entry point, with 'staddr' recalculated
 * to indicate the offset of the data buffer, and second we copy the table.
 */
static int
smb_uiomove(smb_clone_t *cp, uio_t *uio)
{
	off_t off = uio->uio_offset;
	size_t len = uio->uio_resid;
	int err = 0;

	if (off + len > cp->c_eplen + cp->c_stlen)
		len = cp->c_eplen + cp->c_stlen - off;

	if (off < cp->c_eplen) {
		smbios_entry_t *ep = kmem_zalloc(cp->c_eplen, KM_SLEEP);
		size_t eprlen = MIN(len, cp->c_eplen - off);

		smbios_info_smbios(cp->c_hdl, ep);
		ep->smbe_staddr = (uint32_t)cp->c_eplen;
		smbios_checksum(cp->c_hdl, ep);

		err = uiomove((char *)ep + off, eprlen, UIO_READ, uio);
		kmem_free(ep, cp->c_eplen);

		off += eprlen;
		len -= eprlen;
	}

	if (err == 0 && off >= cp->c_eplen) {
		char *buf = (char *)smbios_buf(cp->c_hdl);
		size_t bufoff = off - cp->c_eplen;

		err = uiomove(buf + bufoff,
		    MIN(len, cp->c_stlen - bufoff), UIO_READ, uio);
	}

	return (err);
}
Exemple #4
0
int
smbios_write(smbios_hdl_t *shp, int fd)
{
	smbios_entry_t ep;
	off64_t off = lseek64(fd, 0, SEEK_CUR) + P2ROUNDUP(sizeof (ep), 16);

	if (off > UINT32_MAX)
		return (smb_set_errno(shp, EOVERFLOW));

	bcopy(&shp->sh_ent, &ep, sizeof (ep));
	ep.smbe_staddr = (uint32_t)off;
	smbios_checksum(shp, &ep);

	if (smbios_xwrite(shp, fd, &ep, sizeof (ep)) == -1 ||
	    lseek64(fd, off, SEEK_SET) != off ||
	    smbios_xwrite(shp, fd, shp->sh_buf, shp->sh_buflen) == -1)
		return (-1);

	return (0);
}
Exemple #5
0
smbios_hdl_t *
smbios_bufopen(const smbios_entry_t *ep, const void *buf, size_t len,
    int version, int flags, int *errp)
{
	smbios_hdl_t *shp = smb_zalloc(sizeof (smbios_hdl_t));
	const smb_header_t *hp, *nhp;
	const uchar_t *p, *q, *s;
	uint_t i, h;

	switch (version) {
	case SMB_VERSION_23:
	case SMB_VERSION_24:
	case SMB_VERSION_25:
	case SMB_VERSION_26:
	case SMB_VERSION_27:
	case SMB_VERSION_28:
		break;
	default:
		return (smb_open_error(shp, errp, ESMB_VERSION));
	}

	if (ep == NULL || buf == NULL || len == 0 || (flags & ~SMB_O_MASK))
		return (smb_open_error(shp, errp, ESMB_INVAL));

	if (shp == NULL)
		return (smb_open_error(shp, errp, ESMB_NOMEM));

	if (_smb_debug)
		shp->sh_flags |= SMB_FL_DEBUG;

	if (strncmp(ep->smbe_eanchor, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN))
		return (smb_open_error(shp, errp, ESMB_HEADER));

	if (strncmp(ep->smbe_ianchor, SMB_ENTRY_IANCHOR, SMB_ENTRY_IANCHORLEN))
		return (smb_open_error(shp, errp, ESMB_HEADER));

	smb_dprintf(shp, "opening SMBIOS version %u.%u bcdrev 0x%x\n",
	    ep->smbe_major, ep->smbe_minor, ep->smbe_bcdrev);

	if (!(flags & SMB_O_NOVERS)) {
		if (ep->smbe_major > SMB_MAJOR(SMB_VERSION))
			return (smb_open_error(shp, errp, ESMB_NEW));

		if (ep->smbe_major < SMB_MAJOR(SMB_VERSION_23) || (
		    ep->smbe_major == SMB_MAJOR(SMB_VERSION_23) &&
		    ep->smbe_minor < SMB_MINOR(SMB_VERSION_23)))
			return (smb_open_error(shp, errp, ESMB_OLD));
	}

	if (len < sizeof (smb_header_t) ||
	    ep->smbe_stlen < sizeof (smb_header_t) || len < ep->smbe_stlen)
		return (smb_open_error(shp, errp, ESMB_SHORT));

	if (!(flags & SMB_O_NOCKSUM)) {
		uint8_t esum = 0, isum = 0;
		q = (uchar_t *)ep;

		for (p = q; p < q + ep->smbe_elen; p++)
			esum += *p;

		for (p = (uchar_t *)ep->smbe_ianchor; p < q + sizeof (*ep); p++)
			isum += *p;

		if (esum != 0 || isum != 0) {
			smb_dprintf(shp, "bad cksum: e=%x i=%x\n", esum, isum);
			return (smb_open_error(shp, errp, ESMB_CKSUM));
		}
	}

	/*
	 * Copy the entry point into our handle.  The underlying entry point
	 * may be larger than our structure definition, so reset smbe_elen
	 * to our internal size and recompute good checksums for our copy.
	 */
	bcopy(ep, &shp->sh_ent, sizeof (smbios_entry_t));
	shp->sh_ent.smbe_elen = sizeof (smbios_entry_t);
	smbios_checksum(shp, &shp->sh_ent);

	shp->sh_buf = buf;
	shp->sh_buflen = len;
	shp->sh_structs = smb_alloc(sizeof (smb_struct_t) * ep->smbe_stnum);
	shp->sh_nstructs = 0;
	shp->sh_hashlen = _smb_hashlen;
	shp->sh_hash = smb_zalloc(sizeof (smb_struct_t *) * shp->sh_hashlen);
	shp->sh_libvers = version;
	shp->sh_smbvers = SMB_MAJMIN(ep->smbe_major, ep->smbe_minor);

	if (shp->sh_structs == NULL || shp->sh_hash == NULL)
		return (smb_open_error(shp, errp, ESMB_NOMEM));

	hp = shp->sh_buf;
	q = (const uchar_t *)buf + MIN(ep->smbe_stlen, len);

	for (i = 0; i < ep->smbe_stnum; i++, hp = nhp) {
		smb_struct_t *stp = &shp->sh_structs[i];
		uint_t n = 0;

		if ((const uchar_t *)hp + sizeof (smb_header_t) > q)
			return (smb_open_error(shp, errp, ESMB_CORRUPT));

		smb_dprintf(shp, "struct [%u] type %u len %u hdl %u at %p\n",
		    i, hp->smbh_type, hp->smbh_len, hp->smbh_hdl, (void *)hp);

		if (hp->smbh_type == SMB_TYPE_EOT)
			break; /* ignore any entries beyond end-of-table */

		if ((const uchar_t *)hp + hp->smbh_len > q - 2)
			return (smb_open_error(shp, errp, ESMB_CORRUPT));

		h = hp->smbh_hdl & (shp->sh_hashlen - 1);
		p = s = (const uchar_t *)hp + hp->smbh_len;

		while (p <= q - 2 && (p[0] != '\0' || p[1] != '\0')) {
			if (*p++ == '\0')
				n++; /* count strings until \0\0 delimiter */
		}

		if (p > q - 2)
			return (smb_open_error(shp, errp, ESMB_CORRUPT));

		if (p > s)
			n++; /* add one for final string in string table */

		stp->smbst_hdr = hp;
		stp->smbst_str = s;
		stp->smbst_end = p;
		stp->smbst_next = shp->sh_hash[h];
		stp->smbst_strtab = smb_alloc(sizeof (uint16_t) * n);
		stp->smbst_strtablen = n;

		if (n != 0 && stp->smbst_strtab == NULL)
			return (smb_open_error(shp, errp, ESMB_NOMEM));

		shp->sh_hash[h] = stp;
		nhp = (void *)(p + 2);
		shp->sh_nstructs++;

		for (n = 0, p = s; n < stp->smbst_strtablen; p++) {
			if (*p == '\0') {
				stp->smbst_strtab[n++] =
				    (uint16_t)(s - stp->smbst_str);
				s = p + 1;
			}
		}
	}

	if (flags & SMB_O_ZIDS)
		smb_strip(shp);

	return (shp);
}