diff options
| author | Mark Johnson <Mark.Johnson@Sun.COM> | 2008-09-15 15:09:45 -0700 | 
|---|---|---|
| committer | Mark Johnson <Mark.Johnson@Sun.COM> | 2008-09-15 15:09:45 -0700 | 
| commit | adc586debf12d2592024c0b8b9e44ffa104f858c (patch) | |
| tree | 189b4a865d30882c4001014b69447e6bdaaa46f7 /usr/src | |
| parent | 875a4abcc45eff5fe347622080ebe938010f5acb (diff) | |
| download | illumos-joyent-adc586debf12d2592024c0b8b9e44ffa104f858c.tar.gz | |
6747590 microcode update support for AMD
Contributed by Hans Rosenfeld <hans.rosenfeld@amd.com>
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/cmd/boot/bootadm/bootadm.c | 5 | ||||
| -rw-r--r-- | usr/src/cmd/ucodeadm/ucodeadm.c | 189 | ||||
| -rw-r--r-- | usr/src/common/ucode/ucode_utils.c | 100 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/ucode.h | 147 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/os/microcode.c | 826 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/os/mp_startup.c | 2 | ||||
| -rw-r--r-- | usr/src/uts/intel/io/ucode_drv.c | 8 | ||||
| -rw-r--r-- | usr/src/uts/intel/sys/controlregs.h | 5 | ||||
| -rw-r--r-- | usr/src/uts/intel/sys/x86_archext.h | 2 | 
9 files changed, 936 insertions, 348 deletions
| diff --git a/usr/src/cmd/boot/bootadm/bootadm.c b/usr/src/cmd/boot/bootadm/bootadm.c index bea2a8a28e..e78f257cae 100644 --- a/usr/src/cmd/boot/bootadm/bootadm.c +++ b/usr/src/cmd/boot/bootadm/bootadm.c @@ -7859,8 +7859,9 @@ ucode_install(char *root)  		struct stat fstatus, tstatus;  		struct utimbuf u_times; -		(void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.txt", -		    bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr); +		(void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.%s", +		    bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr, +		    ucode_vendors[i].extstr);  		if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode)))  			continue; diff --git a/usr/src/cmd/ucodeadm/ucodeadm.c b/usr/src/cmd/ucodeadm/ucodeadm.c index 0100bd15d7..765099dd09 100644 --- a/usr/src/cmd/ucodeadm/ucodeadm.c +++ b/usr/src/cmd/ucodeadm/ucodeadm.c @@ -19,12 +19,10 @@   * CDDL HEADER END   */  /* - * Copyright 2007 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */ -#pragma ident	"%Z%%M%	%I%	%E% SMI" -  #include <sys/types.h>  #include <sys/processor.h>  #include <sys/ucode.h> @@ -60,6 +58,19 @@ static char	ucode_install_path[] = UCODE_INSTALL_PATH;  static int	ucode_debug = 0; +static int ucode_convert_amd(const char *, uint8_t *, size_t); +static int ucode_convert_intel(const char *, uint8_t *, size_t); + +static ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *); +static ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *); + +static const struct ucode_ops ucode_ops[] = { +	{ ucode_convert_intel, ucode_gen_files_intel, ucode_validate_intel }, +	{ ucode_convert_amd, ucode_gen_files_amd, ucode_validate_amd }, +}; + +const struct ucode_ops *ucode; +  static void  dprintf(const char *format, ...)  { @@ -81,20 +92,19 @@ usage(int verbose)  		    gettext("\t\t Shows running microcode version.\n\n"));  	} -	(void) fprintf(stderr, "\t%s -u microcode-text-file\n", cmdname); +	(void) fprintf(stderr, "\t%s -u microcode-file\n", cmdname);  	if (verbose) {  		(void) fprintf(stderr, gettext("\t\t Updates microcode to the "  		    "latest matching version found in\n" -		    "\t\t microcode-text-file.\n\n")); +		    "\t\t microcode-file.\n\n"));  	} -	(void) fprintf(stderr, "\t%s -i [-R path] microcode-text-file\n", -	    cmdname); +	(void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname);  	if (verbose) {  		(void) fprintf(stderr, gettext("\t\t Installs microcode to be " -		    "used for subsequent boots. Microcode\n" -		    "\t\t text file name must start with vendor name, " -		    "such as \"intel\".\n\n")); +		    "used for subsequent boots.\n\n")); +		(void) fprintf(stderr, gettext("Microcode file name must start " +		    "with vendor name, such as \"intel\" or \"amd\".\n\n"));  	}  } @@ -113,7 +123,25 @@ ucode_perror(const char *str, ucode_errno_t rc)   * Return the number of characters read.   */  static int -ucode_convert(const char *infile, uint8_t *buf, size_t size) +ucode_convert_amd(const char *infile, uint8_t *buf, size_t size) +{ +	int fd; + +	if (infile == NULL || buf == NULL || size == 0) +		return (0); + +	if ((fd = open(infile, O_RDONLY)) < 0) +		return (0); + +	size = read(fd, buf, size); + +	(void) close(fd); + +	return (size); +} + +static int +ucode_convert_intel(const char *infile, uint8_t *buf, size_t size)  {  	char	linebuf[LINESIZE];  	FILE	*infd = NULL; @@ -173,11 +201,11 @@ ucode_convert(const char *infile, uint8_t *buf, size_t size)   * Returns 0 if no need to update the link; -1 otherwise   */  static int -ucode_should_update(char *filename, uint32_t new_rev) +ucode_should_update_intel(char *filename, uint32_t new_rev)  {  	int		fd;  	struct stat	statbuf; -	ucode_header_t	header; +	ucode_header_intel_t header;  	/*  	 * If the file or link already exists, check to see if @@ -205,7 +233,64 @@ ucode_should_update(char *filename, uint32_t new_rev)   * Generate microcode binary files.  Must be called after ucode_validate().   */  static ucode_errno_t -ucode_gen_files(uint8_t *buf, int size, char *path) +ucode_gen_files_amd(uint8_t *buf, int size, char *path) +{ +	/* LINTED: pointer alignment */ +	uint32_t *ptr = (uint32_t *)buf; +	int plen = strlen(path); +	int fd, count, counter; +	ucode_header_amd_t *uh; +	int last_cpu_rev = 0; + +	/* skip over magic number & equivalence table header */ +	ptr += 2; size -= 8; + +	count = *ptr++; size -= 4; + +	/* equivalence table uses special name */ +	(void) strlcat(path, "/equivalence-table", PATH_MAX); + +	for (;;) { +		dprintf("path = %s\n", path); +		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, +		    S_IRUSR | S_IRGRP | S_IROTH); + +		if (fd == -1) { +			ucode_perror(path, EM_SYS); +			return (EM_SYS); +		} + +		if (write(fd, ptr, count) != count) { +			(void) close(fd); +			ucode_perror(path, EM_SYS); +			return (EM_SYS); +		} + +		(void) close(fd); +		ptr += count >> 2; size -= count; + +		if (!size) +			return (EM_OK); + +		ptr++; size -= 4; +		count = *ptr++; size -= 4; + +		/* construct name from header information */ +		uh = (ucode_header_amd_t *)ptr; + +		if (uh->uh_cpu_rev != last_cpu_rev) { +			last_cpu_rev = uh->uh_cpu_rev; +			counter = 0; +		} + +		path[plen] = '\0'; +		(void) snprintf(path + plen, PATH_MAX - plen, "/%04X-%02X", +		    uh->uh_cpu_rev, counter++); +	} +} + +static ucode_errno_t +ucode_gen_files_intel(uint8_t *buf, int size, char *path)  {  	int	remaining;  	char	common_path[PATH_MAX]; @@ -226,11 +311,13 @@ ucode_gen_files(uint8_t *buf, int size, char *path)  		char		name[PATH_MAX];  		int		i;  		uint8_t		*curbuf = &buf[size - remaining]; -		ucode_header_t	*uhp = (ucode_header_t *)(intptr_t)curbuf; -		ucode_ext_table_t *extp; +		ucode_header_intel_t	*uhp; +		ucode_ext_table_intel_t *extp; + +		uhp = (ucode_header_intel_t *)(intptr_t)curbuf; -		total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); -		body_size = UCODE_BODY_SIZE(uhp->uh_body_size); +		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); +		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);  		remaining -= total_size; @@ -238,7 +325,7 @@ ucode_gen_files(uint8_t *buf, int size, char *path)  		    common_path, uhp->uh_signature, uhp->uh_proc_flags);  		dprintf("firstname = %s\n", firstname); -		if (ucode_should_update(firstname, uhp->uh_rev) != 0) { +		if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) {  			int fd;  			/* Remove the existing one first */ @@ -275,7 +362,7 @@ ucode_gen_files(uint8_t *buf, int size, char *path)  			dprintf("proc_flags = %x, platid = %x, name = %s\n",  			    uhp->uh_proc_flags, platid, name); -			if (ucode_should_update(name, uhp->uh_rev) != 0) { +			if (ucode_should_update_intel(name, uhp->uh_rev) != 0) {  				/* Remove the existing one first */  				(void) unlink(name); @@ -290,17 +377,17 @@ ucode_gen_files(uint8_t *buf, int size, char *path)  				break;  		} -		offset = UCODE_HEADER_SIZE + body_size; +		offset = UCODE_HEADER_SIZE_INTEL + body_size;  		/* Check to see if there is extended signature table */  		if (total_size == offset)  			continue;  		/* There is extended signature table.  More processing. */ -		extp = (ucode_ext_table_t *)(uintptr_t)&curbuf[offset]; +		extp = (ucode_ext_table_intel_t *)(uintptr_t)&curbuf[offset];  		for (i = 0; i < extp->uet_count; i++) { -			ucode_ext_sig_t *uesp = &extp->uet_ext_sig[i]; +			ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i];  			int j;  			for (j = 0; j < 8; j++) { @@ -313,8 +400,8 @@ ucode_gen_files(uint8_t *buf, int size, char *path)  				    "%s/%08X-%02X", path, extp->uet_ext_sig[i],  				    id); -				if (ucode_should_update(name, uhp->uh_rev) != -				    0) { +				if (ucode_should_update_intel(name, uhp->uh_rev) +				    != 0) {  					/* Remove the existing one first */  					(void) unlink(name); @@ -460,6 +547,29 @@ main(int argc, char *argv[])  	 * Convert from text format to binary format  	 */  	if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) { +		int i; +		UCODE_VENDORS; + +		for (i = 0; ucode_vendors[i].filestr != NULL; i++) { +			dprintf("i = %d, filestr = %s, filename = %s\n", +			    i, ucode_vendors[i].filestr, filename); +			if (strncasecmp(ucode_vendors[i].filestr, +			    basename(filename), +			    strlen(ucode_vendors[i].filestr)) == 0) { +				ucode = &ucode_ops[i]; +				(void) strncpy(ucode_vendor_str, +				    ucode_vendors[i].vendorstr, +				    sizeof (ucode_vendor_str)); +				break; +			} +		} + +		if (ucode_vendors[i].filestr == NULL) { +			rc = EM_NOVENDOR; +			ucode_perror(basename(filename), rc); +			goto err_out; +		} +  		if ((stat(filename, &filestat)) < 0) {  			rc = EM_SYS;  			ucode_perror(filename, rc); @@ -479,7 +589,7 @@ main(int argc, char *argv[])  			goto err_out;  		} -		ucode_size = ucode_convert(filename, buf, filestat.st_size); +		ucode_size = ucode->convert(filename, buf, filestat.st_size);  		dprintf("ucode_size = %d\n", ucode_size); @@ -489,7 +599,7 @@ main(int argc, char *argv[])  			goto err_out;  		} -		if ((rc = ucode_validate(buf, ucode_size)) != EM_OK) { +		if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) {  			ucode_perror(filename, rc);  			goto err_out;  		} @@ -500,29 +610,6 @@ main(int argc, char *argv[])  	 * "intel" for Intel microcode, and "amd" for AMD microcode.  	 */  	if (action & UCODE_OPT_INSTALL) { -		int i; -		UCODE_VENDORS; - -		for (i = 0; ucode_vendors[i].filestr != NULL; i++) { -			dprintf("i = %d, filestr = %s, filename = %s\n", -			    i, ucode_vendors[i].filestr, filename); -			if (strncasecmp(ucode_vendors[i].filestr, -			    basename(filename), -			    strlen(ucode_vendors[i].filestr)) == 0) { - -				(void) strncpy(ucode_vendor_str, -				    ucode_vendors[i].vendorstr, -				    sizeof (ucode_vendor_str)); -				break; -			} -		} - -		if (ucode_vendors[i].filestr == NULL) { -			rc = EM_NOVENDOR; -			ucode_perror(basename(filename), rc); -			goto err_out; -		} -  		/*  		 * If no path is provided by the -R option, put the files in  		 * /ucode_install_path/ucode_vendor_str/. @@ -544,7 +631,7 @@ main(int argc, char *argv[])  			goto err_out;  		} -		rc = ucode_gen_files(buf, ucode_size, path); +		rc = ucode->gen_files(buf, ucode_size, path);  		goto err_out;  	} diff --git a/usr/src/common/ucode/ucode_utils.c b/usr/src/common/ucode/ucode_utils.c index 48198a16e9..5878f4a4af 100644 --- a/usr/src/common/ucode/ucode_utils.c +++ b/usr/src/common/ucode/ucode_utils.c @@ -20,12 +20,10 @@   */  /* - * Copyright 2007 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */ -#pragma ident	"%Z%%M%	%I%	%E% SMI" -  #include <sys/types.h>  #include <sys/ucode.h>  #ifdef	_KERNEL @@ -46,7 +44,7 @@   * Returns EM_OK on success, EM_HEADER on failure.   */  ucode_errno_t -ucode_header_validate(ucode_header_t *uhp) +ucode_header_validate_intel(ucode_header_intel_t *uhp)  {  	uint32_t header_size, body_size, total_size; @@ -59,9 +57,9 @@ ucode_header_validate(ucode_header_t *uhp)  	if (uhp->uh_header_ver != 0x1)  		return (EM_HEADER); -	header_size = UCODE_HEADER_SIZE; -	total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); -	body_size = UCODE_BODY_SIZE(uhp->uh_body_size); +	header_size = UCODE_HEADER_SIZE_INTEL; +	total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); +	body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);  	/*  	 * The body size field of the microcode code header specifies the size @@ -91,7 +89,7 @@ ucode_header_validate(ucode_header_t *uhp)  	 */  	if (total_size > (header_size + body_size)) {  		if ((total_size - body_size - header_size - -		    UCODE_EXT_TABLE_SIZE) % UCODE_EXT_SIG_SIZE) { +		    UCODE_EXT_TABLE_SIZE_INTEL) % UCODE_EXT_SIG_SIZE_INTEL) {  			return (EM_HEADER);  		} @@ -104,7 +102,7 @@ ucode_header_validate(ucode_header_t *uhp)   * Returns checksum.   */  uint32_t -ucode_checksum(uint32_t sum, uint32_t size, uint8_t *code) +ucode_checksum_intel(uint32_t sum, uint32_t size, uint8_t *code)  {  	int i;  	uint32_t *lcode = (uint32_t *)(intptr_t)code; @@ -117,9 +115,65 @@ ucode_checksum(uint32_t sum, uint32_t size, uint8_t *code)  }  ucode_errno_t -ucode_validate(uint8_t *ucodep, int size) +ucode_validate_amd(uint8_t *ucodep, int size) +{ +	/* LINTED: pointer alignment */ +	uint32_t *ptr = (uint32_t *)ucodep; +	uint32_t count; + +	if (ucodep == NULL || size <= 0) +		return (EM_INVALIDARG); + +	/* Magic Number: "AMD\0" */ +	size -= 4; +	if (*ptr++ != 0x00414d44) +		return (EM_FILEFORMAT); + +	/* equivalence table */ +	size -= 4; +	if (*ptr++) +		return (EM_FILEFORMAT); + +	size -= 4; +	if (((count = *ptr++) > size) || (count % 16)) +		return (EM_FILEFORMAT); + +	/* LINTED: pointer alignment */ +	ptr = (uint32_t *)(((uint8_t *)ptr) + count); +	size -= count; + +	/* +	 * minimum valid size: +	 * - type and size fields (8 bytes) +	 * - patch header (64 bytes) +	 * - one patch triad (28 bytes) +	 */ +	while (size >= 100) { +		/* microcode patch */ +		size -= 4; +		if (*ptr++ != 1) +			return (EM_FILEFORMAT); + +		size -= 4; +		if (((count = *ptr++) > size) || +		    ((count - sizeof (ucode_header_amd_t)) % 28)) +			return (EM_FILEFORMAT); + +		/* LINTED: pointer alignment */ +		ptr = (uint32_t *)(((uint8_t *)ptr) + count); +		size -= count; +	} + +	if (size) +		return (EM_FILEFORMAT); + +	return (EM_OK); +} + +ucode_errno_t +ucode_validate_intel(uint8_t *ucodep, int size)  { -	uint32_t header_size = UCODE_HEADER_SIZE; +	uint32_t header_size = UCODE_HEADER_SIZE_INTEL;  	int remaining;  	if (ucodep == NULL || size <= 0) @@ -127,36 +181,38 @@ ucode_validate(uint8_t *ucodep, int size)  	for (remaining = size; remaining > 0; ) {  		uint32_t total_size, body_size, ext_size; -		ucode_header_t *uhp; +		ucode_header_intel_t *uhp;  		uint8_t *curbuf = &ucodep[size - remaining];  		ucode_errno_t rc; -		uhp = (ucode_header_t *)(intptr_t)curbuf; +		uhp = (ucode_header_intel_t *)(intptr_t)curbuf; -		if ((rc = ucode_header_validate(uhp)) != EM_OK) +		if ((rc = ucode_header_validate_intel(uhp)) != EM_OK)  			return (rc); -		total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); +		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); -		if (ucode_checksum(0, total_size, curbuf)) +		if (ucode_checksum_intel(0, total_size, curbuf))  			return (EM_CHECKSUM); -		body_size = UCODE_BODY_SIZE(uhp->uh_body_size); +		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);  		ext_size = total_size - (header_size + body_size);  		if (ext_size > 0) {  			uint32_t i; -			if (ucode_checksum(0, ext_size, +			if (ucode_checksum_intel(0, ext_size,  			    &curbuf[header_size + body_size])) {  				return (EM_CHECKSUM);  			} -			ext_size -= UCODE_EXT_TABLE_SIZE; -			for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE; i++) { -				if (ucode_checksum(0, UCODE_EXT_SIG_SIZE, +			ext_size -= UCODE_EXT_TABLE_SIZE_INTEL; +			for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE_INTEL; +			    i++) { +				if (ucode_checksum_intel(0, +				    UCODE_EXT_SIG_SIZE_INTEL,  				    &curbuf[total_size - ext_size + -				    i * UCODE_EXT_SIG_SIZE])) { +				    i * UCODE_EXT_SIG_SIZE_INTEL])) {  					return (EM_CHECKSUM);  				} diff --git a/usr/src/uts/common/sys/ucode.h b/usr/src/uts/common/sys/ucode.h index 296a51f961..0f37745cae 100644 --- a/usr/src/uts/common/sys/ucode.h +++ b/usr/src/uts/common/sys/ucode.h @@ -19,15 +19,16 @@   * CDDL HEADER END   */  /* - * Copyright 2007 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */  #ifndef	_SYS_UCODE_H  #define	_SYS_UCODE_H -#pragma ident	"%Z%%M%	%I%	%E% SMI" - +#ifdef _KERNEL +#include <sys/cpuvar.h> +#endif  #include <sys/types.h>  #include <sys/priv.h>  #include <sys/processor.h> @@ -92,9 +93,41 @@ struct ucode_write_struct32 {  #endif	/* _SYSCALL32_IMPL */  /* - * Microcode file information + * AMD Microcode file information   */ -typedef struct ucode_header { +typedef struct ucode_header_amd { +	uint32_t uh_date; +	uint32_t uh_patch_id; +	uint32_t uh_internal; /* patch data id & length, init flag */ +	uint32_t uh_cksum; +	uint32_t uh_nb_id; +	uint32_t uh_sb_id; +	uint16_t uh_cpu_rev; +	uint8_t  uh_nb_rev; +	uint8_t  uh_sb_rev; +	uint32_t uh_bios_rev; +	uint32_t uh_match[8]; +} ucode_header_amd_t; + +typedef struct ucode_file_amd { +	ucode_header_amd_t uf_header; +	uint8_t uf_data[896]; +	uint8_t uf_resv[896]; +	uint8_t uf_code_present; +	uint8_t uf_code[191]; +} ucode_file_amd_t; + +typedef struct ucode_eqtbl_amd { +	uint32_t ue_inst_cpu; +	uint32_t ue_fixed_mask; +	uint32_t ue_fixed_comp; +	uint32_t ue_equiv_cpu; +} ucode_eqtbl_amd_t; + +/* + * Intel Microcode file information + */ +typedef struct ucode_header_intel {  	uint32_t	uh_header_ver;  	uint32_t	uh_rev;  	uint32_t	uh_date; @@ -105,25 +138,33 @@ typedef struct ucode_header {  	uint32_t	uh_body_size;  	uint32_t	uh_total_size;  	uint32_t	uh_reserved[3]; -} ucode_header_t; +} ucode_header_intel_t; -typedef struct ucode_ext_sig { +typedef struct ucode_ext_sig_intel {  	uint32_t	ues_signature;  	uint32_t	ues_proc_flags;  	uint32_t	ues_checksum; -} ucode_ext_sig_t; +} ucode_ext_sig_intel_t; -typedef struct ucode_ext_table { +typedef struct ucode_ext_table_intel {  	uint32_t	uet_count;  	uint32_t	uet_checksum;  	uint32_t	uet_reserved[3]; -	ucode_ext_sig_t uet_ext_sig[1]; -} ucode_ext_table_t; +	ucode_ext_sig_intel_t uet_ext_sig[1]; +} ucode_ext_table_intel_t; -typedef struct ucode_file { -	ucode_header_t		uf_header; +typedef struct ucode_file_intel { +	ucode_header_intel_t	*uf_header;  	uint8_t			*uf_body; -	ucode_ext_table_t	*uf_ext_table; +	ucode_ext_table_intel_t	*uf_ext_table; +} ucode_file_intel_t; + +/* + * common container + */ +typedef union ucode_file { +	ucode_file_amd_t *amd; +	ucode_file_intel_t intel;  } ucode_file_t; @@ -139,14 +180,14 @@ typedef struct ucode_file {  #define	UCODE_MAX_PATH_LEN	(PATH_MAX - UCODE_COMMON_NAME_LEN) -#define	UCODE_HEADER_SIZE	(sizeof (struct ucode_header)) -#define	UCODE_EXT_TABLE_SIZE	(20)	/* 20-bytes */ -#define	UCODE_EXT_SIG_SIZE	(sizeof (struct ucode_ext_sig)) +#define	UCODE_HEADER_SIZE_INTEL		(sizeof (struct ucode_header_intel)) +#define	UCODE_EXT_TABLE_SIZE_INTEL	(20)	/* 20-bytes */ +#define	UCODE_EXT_SIG_SIZE_INTEL	(sizeof (struct ucode_ext_sig_intel))  #define	UCODE_KB(a)	((a) << 10)	/* KB */  #define	UCODE_MB(a)	((a) << 20)	/* MB */  #define	UCODE_DEFAULT_TOTAL_SIZE	UCODE_KB(2) -#define	UCODE_DEFAULT_BODY_SIZE		(UCODE_KB(2) - UCODE_HEADER_SIZE) +#define	UCODE_DEFAULT_BODY_SIZE		(UCODE_KB(2) - UCODE_HEADER_SIZE_INTEL)  /*   * For a single microcode file, the minimum size is 1K, maximum size is 16K. @@ -164,35 +205,87 @@ typedef struct ucode_file {  #define	UCODE_SIZE_CONVERT(size, default_size) \  	((size) == 0 ? (default_size) : (size)) -#define	UCODE_BODY_SIZE(size) \ +#define	UCODE_BODY_SIZE_INTEL(size) \  	UCODE_SIZE_CONVERT((size), UCODE_DEFAULT_BODY_SIZE) -#define	UCODE_TOTAL_SIZE(size) \ +#define	UCODE_TOTAL_SIZE_INTEL(size)			\  	UCODE_SIZE_CONVERT((size), UCODE_DEFAULT_TOTAL_SIZE) -#define	UCODE_MATCH(sig1, sig2, pf1, pf2) \ +#define	UCODE_MATCH_INTEL(sig1, sig2, pf1, pf2) \  	(((sig1) == (sig2)) && \  	(((pf1) & (pf2)) || (((pf1) == 0) && ((pf2) == 0)))) -extern ucode_errno_t ucode_header_validate(ucode_header_t *); -extern uint32_t ucode_checksum(uint32_t, uint32_t, uint8_t *); -extern ucode_errno_t ucode_validate(uint8_t *, int); +extern ucode_errno_t ucode_header_validate_intel(ucode_header_intel_t *); +extern uint32_t ucode_checksum_intel(uint32_t, uint32_t, uint8_t *); + +extern ucode_errno_t ucode_validate_amd(uint8_t *, int); +extern ucode_errno_t ucode_validate_intel(uint8_t *, int); + +#ifdef _KERNEL  extern ucode_errno_t ucode_get_rev(uint32_t *);  extern ucode_errno_t ucode_update(uint8_t *, int); +/* + * Microcode specific information per core + */ +typedef struct cpu_ucode_info { +	uint32_t	cui_platid;	/* platform id */ +	uint32_t	cui_rev;	/* microcode revision */ +} cpu_ucode_info_t; + +/* + * Data structure used for xcall + */ +typedef struct ucode_update { +	uint32_t		sig;	/* signature */ +	cpu_ucode_info_t	info;	/* ucode info */ +	uint32_t		expected_rev; +	uint32_t		new_rev; +	uint8_t			*ucodep; /* pointer to ucode */ +	uint32_t		usize; +} ucode_update_t; + +/* + * Microcode kernel operations + */ +struct ucode_ops { +	uint32_t	write_msr; +	int		(*capable)(cpu_t *); +	void		(*file_reset)(ucode_file_t *, processorid_t); +	void		(*read_rev)(cpu_ucode_info_t *); +	uint32_t	(*load)(ucode_file_t *, cpu_ucode_info_t *, cpu_t *); +	ucode_errno_t	(*validate)(uint8_t *, int); +	ucode_errno_t	(*extract)(ucode_update_t *, uint8_t *, int); +	ucode_errno_t	(*locate)(cpu_t *, cpu_ucode_info_t *, ucode_file_t *); +}; +#else +  #define	UCODE_MAX_VENDORS_NAME_LEN		20  #define	UCODE_VENDORS				\  static struct {					\  	char *filestr;				\ +	char *extstr;				\  	char *vendorstr;			\  	int  supported;				\  } ucode_vendors[] = {				\ -	{ "intel", "GenuineIntel", 1 },		\ -	{ "amd", "AuthenticAMD", 0 },		\ -	{ NULL, NULL, 0 }				\ +	{ "intel", "txt", "GenuineIntel", 1 },	\ +	{ "amd", "bin", "AuthenticAMD", 1 },	\ +	{ NULL, NULL, NULL, 0 }			\  } +/* + * Microcode user operations + */ +struct ucode_ops { +	int		(*convert)(const char *, uint8_t *, size_t); +	ucode_errno_t	(*gen_files)(uint8_t *, int, char *); +	ucode_errno_t	(*validate)(uint8_t *, int); +}; +#endif + +extern const struct ucode_ops *ucode; +  #ifdef __cplusplus  }  #endif diff --git a/usr/src/uts/i86pc/os/microcode.c b/usr/src/uts/i86pc/os/microcode.c index 6474bcce78..7dd2ef2e55 100644 --- a/usr/src/uts/i86pc/os/microcode.c +++ b/usr/src/uts/i86pc/os/microcode.c @@ -48,43 +48,76 @@  #endif  /* - * Microcode specific information per core + * AMD-specific equivalence table   */ -struct cpu_ucode_info { -	uint32_t	cui_platid;	/* platform id */ -	uint32_t	cui_rev;	/* microcode revision */ -}; - -/* - * Data structure used for xcall - */ -struct ucode_update_struct { -	uint32_t		sig;	/* signature */ -	struct cpu_ucode_info	info;	/* ucode info */ -	uint32_t		expected_rev; -	uint32_t		new_rev; -	uint8_t			*ucodep; /* pointer to ucode body */ -}; +static ucode_eqtbl_amd_t *ucode_eqtbl_amd;  /*   * mcpu_ucode_info for the boot CPU.  Statically allocated.   */  static struct cpu_ucode_info cpu_ucode_info0; -static ucode_file_t ucodefile = { 0 }; +static ucode_file_t ucodefile; + +static void* ucode_zalloc(processorid_t, size_t); +static void ucode_free(processorid_t, void *, size_t); + +static int ucode_capable_amd(cpu_t *); +static int ucode_capable_intel(cpu_t *); + +static ucode_errno_t ucode_extract_amd(ucode_update_t *, uint8_t *, int); +static ucode_errno_t ucode_extract_intel(ucode_update_t *, uint8_t *, +    int); + +static void ucode_file_reset_amd(ucode_file_t *, processorid_t); +static void ucode_file_reset_intel(ucode_file_t *, processorid_t); + +static uint32_t ucode_load_amd(ucode_file_t *, cpu_ucode_info_t *, cpu_t *); +static uint32_t ucode_load_intel(ucode_file_t *, cpu_ucode_info_t *, cpu_t *); -static int ucode_capable(cpu_t *); -static void ucode_file_reset(ucode_file_t *, processorid_t); -static ucode_errno_t ucode_match(int, struct cpu_ucode_info *, -    ucode_header_t *, ucode_ext_table_t *); -static ucode_errno_t ucode_locate(cpu_t *, struct cpu_ucode_info *, -    ucode_file_t *); -static void ucode_update_intel(uint8_t *, struct cpu_ucode_info *); -static void ucode_read_rev(struct cpu_ucode_info *);  #ifdef	__xpv -static void ucode_update_xpv(struct ucode_update_struct *, uint8_t *, uint32_t); +static void ucode_load_xpv(ucode_update_t *);  #endif +static int ucode_equiv_cpu_amd(cpu_t *, int *); + +static ucode_errno_t ucode_locate_amd(cpu_t *, cpu_ucode_info_t *, +    ucode_file_t *); +static ucode_errno_t ucode_locate_intel(cpu_t *, cpu_ucode_info_t *, +    ucode_file_t *); + +static ucode_errno_t ucode_match_amd(int, cpu_ucode_info_t *, +    ucode_file_amd_t *, int); +static ucode_errno_t ucode_match_intel(int, cpu_ucode_info_t *, +    ucode_header_intel_t *, ucode_ext_table_intel_t *); + +static void ucode_read_rev_amd(cpu_ucode_info_t *); +static void ucode_read_rev_intel(cpu_ucode_info_t *); + +static const struct ucode_ops ucode_amd = { +	MSR_AMD_PATCHLOADER, +	ucode_capable_amd, +	ucode_file_reset_amd, +	ucode_read_rev_amd, +	ucode_load_amd, +	ucode_validate_amd, +	ucode_extract_amd, +	ucode_locate_amd +}; + +static const struct ucode_ops ucode_intel = { +	MSR_INTC_UCODE_WRITE, +	ucode_capable_intel, +	ucode_file_reset_intel, +	ucode_read_rev_intel, +	ucode_load_intel, +	ucode_validate_intel, +	ucode_extract_intel, +	ucode_locate_intel +}; + +const struct ucode_ops *ucode; +  static const char ucode_failure_fmt[] =  	"cpu%d: failed to update microcode from version 0x%x to 0x%x\n";  static const char ucode_success_fmt[] = @@ -122,42 +155,84 @@ ucode_free_space(cpu_t *cp)   * space allocated for the microcode file.   */  void -ucode_free() +ucode_cleanup() +{ +	ASSERT(ucode); + +	ucode->file_reset(&ucodefile, -1); +} + +/* + * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is + * allocated with BOP_ALLOC() and does not require a free. + */ +static void* +ucode_zalloc(processorid_t id, size_t size) +{ +	if (id) +		return (kmem_zalloc(size, KM_NOSLEEP)); + +	/* BOP_ALLOC() failure results in panic */ +	return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE)); +} + +static void +ucode_free(processorid_t id, void* buf, size_t size)  { -	ucode_file_reset(&ucodefile, -1); +	if (id) +		kmem_free(buf, size);  }  /*   * Check whether or not a processor is capable of microcode operations   * Returns 1 if it is capable, 0 if not. + * + * At this point we only support microcode update for: + * - Intel processors family 6 and above, and + * - AMD processors family 0x10 and above. + * + * We also assume that we don't support a mix of Intel and + * AMD processors in the same box. + * + * An i86xpv guest domain can't update the microcode.   */ +/*ARGSUSED*/  static int -ucode_capable(cpu_t *cp) +ucode_capable_amd(cpu_t *cp)  { -	/* i86xpv guest domain can't update microcode */  #ifndef	__xpv  	extern int xpv_is_hvm;  	if (xpv_is_hvm) {  		return (0);  	} + +	return (cpuid_getfamily(cp) >= 0x10);  #else  	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {  		return (0);  	} -#endif  	/* -	 * At this point we only support microcode update for Intel -	 * processors family 6 and above. -	 * -	 * We also assume that we don't support a mix of Intel and -	 * AMD processors in the same box. +	 * XXPV - change when microcode loading works in dom0. Don't support +	 * microcode loading in dom0 right now for AMD.  	 */ -	if (cpuid_getvendor(cp) != X86_VENDOR_Intel || -	    cpuid_getfamily(cp) < 6) +	return (0); +#endif +} +static int +ucode_capable_intel(cpu_t *cp) +{ +#ifndef	__xpv +	extern int xpv_is_hvm; +	if (xpv_is_hvm) {  		return (0); -	else -		return (1); +	} +#else +	if (!DOMAIN_IS_INITDOMAIN(xen_info)) { +		return (0); +	} +#endif +	return (cpuid_getfamily(cp) >= 6);  }  /* @@ -165,37 +240,124 @@ ucode_capable(cpu_t *cp)   * or when the cached microcode doesn't match the CPU being processed.   */  static void -ucode_file_reset(ucode_file_t *ucodefp, processorid_t id) +ucode_file_reset_amd(ucode_file_t *ufp, processorid_t id)  { -	int total_size, body_size; +	ucode_file_amd_t *ucodefp = ufp->amd;  	if (ucodefp == NULL)  		return; -	total_size = UCODE_TOTAL_SIZE(ucodefp->uf_header.uh_total_size); -	body_size = UCODE_BODY_SIZE(ucodefp->uf_header.uh_body_size); +	ucode_free(id, ucodefp, sizeof (ucode_file_amd_t)); +	ufp->amd = NULL; +} + +static void +ucode_file_reset_intel(ucode_file_t *ufp, processorid_t id) +{ +	ucode_file_intel_t *ucodefp = &ufp->intel; +	int total_size, body_size; + +	if (ucodefp == NULL || ucodefp->uf_header == NULL) +		return; + +	total_size = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size); +	body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size);  	if (ucodefp->uf_body) { -		/* -		 * Space for the boot CPU is allocated with BOP_ALLOC() -		 * and does not require a free. -		 */ -		if (id != 0) -			kmem_free(ucodefp->uf_body, body_size); +		ucode_free(id, ucodefp->uf_body, body_size);  		ucodefp->uf_body = NULL;  	}  	if (ucodefp->uf_ext_table) { -		int size = total_size - body_size - UCODE_HEADER_SIZE; -		/* -		 * Space for the boot CPU is allocated with BOP_ALLOC() -		 * and does not require a free. -		 */ -		if (id != 0) -			kmem_free(ucodefp->uf_ext_table, size); +		int size = total_size - body_size - UCODE_HEADER_SIZE_INTEL; + +		ucode_free(id, ucodefp->uf_ext_table, size);  		ucodefp->uf_ext_table = NULL;  	} -	bzero(&ucodefp->uf_header, UCODE_HEADER_SIZE); +	ucode_free(id, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL); +	ucodefp->uf_header = NULL; +} + +/* + * Find the equivalent CPU id in the equivalence table. + */ +static int +ucode_equiv_cpu_amd(cpu_t *cp, int *eq_sig) +{ +	char name[MAXPATHLEN]; +	intptr_t fd; +	int count; +	int offset = 0, cpi_sig = cpuid_getsig(cp); +	ucode_eqtbl_amd_t *eqtbl = ucode_eqtbl_amd; + +	(void) snprintf(name, MAXPATHLEN, "/%s/%s/equivalence-table", +	    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp)); + +	/* +	 * No kmem_zalloc() etc. available on boot cpu. +	 */ +	if (cp->cpu_id == 0) { +		if ((fd = kobj_open(name)) == -1) +			return (EM_OPENFILE); +		/* ucode_zalloc() cannot fail on boot cpu */ +		eqtbl = ucode_zalloc(cp->cpu_id, sizeof (*eqtbl)); +		ASSERT(eqtbl); +		do { +			count = kobj_read(fd, (int8_t *)eqtbl, +			    sizeof (*eqtbl), offset); +			if (count != sizeof (*eqtbl)) { +				(void) kobj_close(fd); +				return (EM_HIGHERREV); +			} +			offset += count; +		} while (eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig); +		(void) kobj_close(fd); +	} + +	/* +	 * If not already done, load the equivalence table. +	 * Not done on boot CPU. +	 */ +	if (eqtbl == NULL) { +		struct _buf *eq; +		uint64_t size; + +		if ((eq = kobj_open_file(name)) == (struct _buf *)-1) +			return (EM_OPENFILE); + +		if (kobj_get_filesize(eq, &size) < 0) { +			kobj_close_file(eq); +			return (EM_OPENFILE); +		} + +		ucode_eqtbl_amd = kmem_zalloc(size, KM_NOSLEEP); +		if (ucode_eqtbl_amd == NULL) { +			kobj_close_file(eq); +			return (EM_NOMEM); +		} + +		count = kobj_read_file(eq, (char *)ucode_eqtbl_amd, size, 0); +		kobj_close_file(eq); + +		if (count != size) +			return (EM_FILESIZE); +	} + +	/* Get the equivalent CPU id. */ +	if (cp->cpu_id) +		for (eqtbl = ucode_eqtbl_amd; +		    eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig; +		    eqtbl++) +			; + +	*eq_sig = eqtbl->ue_equiv_cpu; +	*eq_sig = ((*eq_sig >> 8) & 0xff00) | (*eq_sig & 0xff); + +	/* No equivalent CPU id found, assume outdated microcode file. */ +	if (*eq_sig == 0) +		return (EM_HIGHERREV); + +	return (EM_OK);  }  /* @@ -205,19 +367,73 @@ ucode_file_reset(ucode_file_t *ucodefp, processorid_t id)   * Return EM_OK on success, corresponding error code on failure.   */  static ucode_errno_t -ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp) +ucode_locate_amd(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp) +{ +	char name[MAXPATHLEN]; +	intptr_t fd; +	int count, i, rc; +	int eq_sig = 0; +	ucode_file_amd_t *ucodefp = ufp->amd; + +	/* get equivalent CPU id */ +	if ((rc = ucode_equiv_cpu_amd(cp, &eq_sig)) != EM_OK) +		return (rc); + +	/* +	 * Allocate a buffer for the microcode patch. If the buffer has been +	 * allocated before, check for a matching microcode to avoid loading +	 * the file again. +	 */ +	if (ucodefp == NULL) +		ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp)); +	else if (ucode_match_amd(eq_sig, uinfop, ucodefp, sizeof (*ucodefp)) +	    == EM_OK) +		return (EM_OK); + +	if (ucodefp == NULL) +		return (EM_NOMEM); + +	ufp->amd = ucodefp; + +	/* +	 * Find the patch for this CPU. The patch files are named XXXX-YY, where +	 * XXXX is the equivalent CPU id and YY is the running patch number. +	 * Patches specific to certain chipsets are guaranteed to have lower +	 * numbers than less specific patches, so we can just load the first +	 * patch that matches. +	 */ + +	for (i = 0; i < 0xff; i++) { +		(void) snprintf(name, MAXPATHLEN, "/%s/%s/%04X-%02X", +		    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), eq_sig, i); +		if ((fd = kobj_open(name)) == -1) +			return (EM_NOMATCH); +		count = kobj_read(fd, (char *)ucodefp, sizeof (*ucodefp), 0); +		(void) kobj_close(fd); + +		if (ucode_match_amd(eq_sig, uinfop, ucodefp, count) == EM_OK) +			return (EM_OK); +	} +	return (EM_NOMATCH); +} + +static ucode_errno_t +ucode_locate_intel(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp)  {  	char		name[MAXPATHLEN];  	intptr_t	fd;  	int		count; -	int		header_size = UCODE_HEADER_SIZE; +	int		header_size = UCODE_HEADER_SIZE_INTEL;  	int		cpi_sig = cpuid_getsig(cp);  	ucode_errno_t	rc = EM_OK; +	ucode_file_intel_t *ucodefp = &ufp->intel; + +	ASSERT(ucode);  	/*  	 * If the microcode matches the CPU we are processing, use it.  	 */ -	if (ucode_match(cpi_sig, uinfop, &ucodefp->uf_header, +	if (ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header,  	    ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) {  		return (EM_OK);  	} @@ -237,14 +453,18 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)  	 * reset the microcode data structure and read in the new  	 * file.  	 */ -	ucode_file_reset(ucodefp, cp->cpu_id); +	ucode->file_reset(ufp, cp->cpu_id); + +	ucodefp->uf_header = ucode_zalloc(cp->cpu_id, header_size); +	if (ucodefp->uf_header == NULL) +		return (EM_NOMEM); -	count = kobj_read(fd, (char *)&ucodefp->uf_header, header_size, 0); +	count = kobj_read(fd, (char *)ucodefp->uf_header, header_size, 0);  	switch (count) { -	case UCODE_HEADER_SIZE: { +	case UCODE_HEADER_SIZE_INTEL: { -		ucode_header_t	*uhp = &ucodefp->uf_header; +		ucode_header_intel_t	*uhp = ucodefp->uf_header;  		uint32_t	offset = header_size;  		int		total_size, body_size, ext_size;  		uint32_t	sum = 0; @@ -252,23 +472,13 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)  		/*  		 * Make sure that the header contains valid fields.  		 */ -		if ((rc = ucode_header_validate(uhp)) == EM_OK) { -			total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); -			body_size = UCODE_BODY_SIZE(uhp->uh_body_size); -			if (cp->cpu_id != 0) { -				if ((ucodefp->uf_body = kmem_zalloc(body_size, -				    KM_NOSLEEP)) == NULL) { -					rc = EM_NOMEM; -					break; -				} -			} else { -				/* -				 * BOP_ALLOC() failure results in panic so we -				 * don't have to check for NULL return. -				 */ -				ucodefp->uf_body = -				    (uint8_t *)BOP_ALLOC(bootops, -				    NULL, body_size, MMU_PAGESIZE); +		if ((rc = ucode_header_validate_intel(uhp)) == EM_OK) { +			total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); +			body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); +			ucodefp->uf_body = ucode_zalloc(cp->cpu_id, body_size); +			if (ucodefp->uf_body == NULL) { +				rc = EM_NOMEM; +				break;  			}  			if (kobj_read(fd, (char *)ucodefp->uf_body, @@ -279,9 +489,9 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)  		if (rc)  			break; -		sum = ucode_checksum(0, header_size, -		    (uint8_t *)&ucodefp->uf_header); -		if (ucode_checksum(sum, body_size, ucodefp->uf_body)) { +		sum = ucode_checksum_intel(0, header_size, +		    (uint8_t *)ucodefp->uf_header); +		if (ucode_checksum_intel(sum, body_size, ucodefp->uf_body)) {  			rc = EM_CHECKSUM;  			break;  		} @@ -295,35 +505,26 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)  		if (ext_size <= 0)  			break; -		if (cp->cpu_id != 0) { -			if ((ucodefp->uf_ext_table = kmem_zalloc(ext_size, -			    KM_NOSLEEP)) == NULL) { -				rc = EM_NOMEM; -				break; -			} -		} else { -			/* -			 * BOP_ALLOC() failure results in panic so we -			 * don't have to check for NULL return. -			 */ -			ucodefp->uf_ext_table = -			    (ucode_ext_table_t *)BOP_ALLOC(bootops, NULL, -			    ext_size, MMU_PAGESIZE); +		ucodefp->uf_ext_table = ucode_zalloc(cp->cpu_id, ext_size); +		if (ucodefp->uf_ext_table == NULL) { +			rc = EM_NOMEM; +			break;  		}  		if (kobj_read(fd, (char *)ucodefp->uf_ext_table,  		    ext_size, offset) != ext_size) {  			rc = EM_FILESIZE; -		} else if (ucode_checksum(0, ext_size, +		} else if (ucode_checksum_intel(0, ext_size,  		    (uint8_t *)(ucodefp->uf_ext_table))) {  			rc = EM_CHECKSUM;  		} else {  			int i; -			ext_size -= UCODE_EXT_TABLE_SIZE; +			ext_size -= UCODE_EXT_TABLE_SIZE_INTEL;  			for (i = 0; i < ucodefp->uf_ext_table->uet_count;  			    i++) { -				if (ucode_checksum(0, UCODE_EXT_SIG_SIZE, +				if (ucode_checksum_intel(0, +				    UCODE_EXT_SIG_SIZE_INTEL,  				    (uint8_t *)(&(ucodefp->uf_ext_table->  				    uet_ext_sig[i])))) {  					rc = EM_CHECKSUM; @@ -344,23 +545,63 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)  	if (rc != EM_OK)  		return (rc); -	rc = ucode_match(cpi_sig, uinfop, &ucodefp->uf_header, +	rc = ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header,  	    ucodefp->uf_ext_table);  	return (rc);  } +static ucode_errno_t +ucode_match_amd(int eq_sig, cpu_ucode_info_t *uinfop, ucode_file_amd_t *ucodefp, +    int size) +{ +	ucode_header_amd_t *uh; + +	if (ucodefp == NULL || size < sizeof (ucode_header_amd_t)) +		return (EM_NOMATCH); + +	/* +	 * Don't even think about loading patches that would require code +	 * execution. +	 */ +	if (size > offsetof(ucode_file_amd_t, uf_code_present) && +	    ucodefp->uf_code_present) +		return (EM_NOMATCH); + +	uh = &ucodefp->uf_header; + +	if (eq_sig != uh->uh_cpu_rev) +		return (EM_NOMATCH); + +	if (uh->uh_nb_id) { +		cmn_err(CE_WARN, "ignoring northbridge-specific ucode: " +		    "chipset id %x, revision %x", uh->uh_nb_id, uh->uh_nb_rev); +		return (EM_NOMATCH); +	} + +	if (uh->uh_sb_id) { +		cmn_err(CE_WARN, "ignoring southbridge-specific ucode: " +		    "chipset id %x, revision %x", uh->uh_sb_id, uh->uh_sb_rev); +		return (EM_NOMATCH); +	} + +	if (uh->uh_patch_id <= uinfop->cui_rev) +		return (EM_HIGHERREV); + +	return (EM_OK); +}  /*   * Returns 1 if the microcode is for this processor; 0 otherwise.   */  static ucode_errno_t -ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop, -    ucode_header_t *uhp, ucode_ext_table_t *uetp) +ucode_match_intel(int cpi_sig, cpu_ucode_info_t *uinfop, +    ucode_header_intel_t *uhp, ucode_ext_table_intel_t *uetp)  { -	ASSERT(uhp); +	if (uhp == NULL) +		return (EM_NOMATCH); -	if (UCODE_MATCH(cpi_sig, uhp->uh_signature, +	if (UCODE_MATCH_INTEL(cpi_sig, uhp->uh_signature,  	    uinfop->cui_platid, uhp->uh_proc_flags)) {  		if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update) @@ -373,11 +614,11 @@ ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,  		int i;  		for (i = 0; i < uetp->uet_count; i++) { -			ucode_ext_sig_t *uesp; +			ucode_ext_sig_intel_t *uesp;  			uesp = &uetp->uet_ext_sig[i]; -			if (UCODE_MATCH(cpi_sig, uesp->ues_signature, +			if (UCODE_MATCH_INTEL(cpi_sig, uesp->ues_signature,  			    uinfop->cui_platid, uesp->ues_proc_flags)) {  				if (uinfop->cui_rev >= uhp->uh_rev && @@ -396,9 +637,10 @@ ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,  static int  ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)  { -	struct ucode_update_struct *uusp = (struct ucode_update_struct *)arg1; -	struct cpu_ucode_info *uinfop = CPU->cpu_m.mcpu_ucode_info; +	ucode_update_t *uusp = (ucode_update_t *)arg1; +	cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info; +	ASSERT(ucode);  	ASSERT(uusp->ucodep);  #ifndef	__xpv @@ -408,65 +650,134 @@ ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)  	 * the threads share the same microcode.  	 */  	if (!ucode_force_update) { -		ucode_read_rev(uinfop); +		ucode->read_rev(uinfop);  		uusp->new_rev = uinfop->cui_rev;  		if (uinfop->cui_rev >= uusp->expected_rev)  			return (0);  	} -	wrmsr(MSR_INTC_UCODE_WRITE, -	    (uint64_t)(intptr_t)(uusp->ucodep)); +	wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep);  #endif -	ucode_read_rev(uinfop); +	ucode->read_rev(uinfop);  	uusp->new_rev = uinfop->cui_rev;  	return (0);  } +/*ARGSUSED*/ +static uint32_t +ucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp) +{ +	ucode_file_amd_t *ucodefp = ufp->amd; +#ifdef	__xpv +	ucode_update_t uus; +#endif -static void -ucode_update_intel(uint8_t *ucode_body, struct cpu_ucode_info *uinfop) +	ASSERT(ucode); +	ASSERT(ucodefp); + +#ifndef	__xpv +	kpreempt_disable(); +	wrmsr(ucode->write_msr, (uintptr_t)ucodefp); +	ucode->read_rev(uinfop); +	kpreempt_enable(); +#else +	uus.ucodep = (uint8_t *)ucodefp; +	uus.usize = sizeof (*ucodefp); +	ucode_load_xpv(&uus); +	ucode->read_rev(uinfop); +	uus.new_rev = uinfop->cui_rev; +#endif + +	return (ucodefp->uf_header.uh_patch_id); +} + +/*ARGSUSED2*/ +static uint32_t +ucode_load_intel(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp)  { +	ucode_file_intel_t *ucodefp = &ufp->intel; +#ifdef __xpv +	uint32_t ext_offset; +	uint32_t body_size; +	uint32_t ext_size; +	uint8_t *ustart; +	uint32_t usize; +	ucode_update_t uus; +#endif + +	ASSERT(ucode); + +#ifdef __xpv +	/* +	 * the hypervisor wants the header, data, and extended +	 * signature tables. We can only get here from the boot +	 * CPU (cpu #0), we don't need to free as ucode_zalloc() will +	 * use BOP_ALLOC(). +	 */ +	usize = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size); +	ustart = ucode_zalloc(cp->cpu_id, usize); +	ASSERT(ustart); + +	body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size); +	ext_offset = body_size + UCODE_HEADER_SIZE_INTEL; +	ext_size = usize - ext_offset; +	ASSERT(ext_size >= 0); + +	(void) memcpy(ustart, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL); +	(void) memcpy(&ustart[UCODE_HEADER_SIZE_INTEL], ucodefp->uf_body, +	    body_size); +	if (ext_size > 0) { +		(void) memcpy(&ustart[ext_offset], +		    ucodefp->uf_ext_table, ext_size); +	} +	uus.ucodep = ustart; +	uus.usize = usize; +	ucode_load_xpv(&uus); +	ucode->read_rev(uinfop); +	uus.new_rev = uinfop->cui_rev; +#else  	kpreempt_disable(); -	wrmsr(MSR_INTC_UCODE_WRITE, (uint64_t)(uintptr_t)ucode_body); -	ucode_read_rev(uinfop); +	wrmsr(ucode->write_msr, (uintptr_t)ucodefp->uf_body); +	ucode->read_rev(uinfop);  	kpreempt_enable(); +#endif + +	return (ucodefp->uf_header->uh_rev);  }  #ifdef	__xpv  static void -ucode_update_xpv(struct ucode_update_struct *uusp, uint8_t *ucode, -    uint32_t size) +ucode_load_xpv(ucode_update_t *uusp)  { -	struct cpu_ucode_info *uinfop;  	xen_platform_op_t op;  	int e;  	ASSERT(DOMAIN_IS_INITDOMAIN(xen_info));  	kpreempt_disable(); -	uinfop = CPU->cpu_m.mcpu_ucode_info;  	op.cmd = XENPF_microcode_update;  	op.interface_version = XENPF_INTERFACE_VERSION;  	/*LINTED: constant in conditional context*/ -	set_xen_guest_handle(op.u.microcode.data, ucode); -	op.u.microcode.length = size; +	set_xen_guest_handle(op.u.microcode.data, uusp->ucodep); +	op.u.microcode.length = uusp->usize;  	e = HYPERVISOR_platform_op(&op);  	if (e != 0) {  		cmn_err(CE_WARN, "hypervisor failed to accept uCode update");  	} -	ucode_read_rev(uinfop); -	if (uusp != NULL) { -		uusp->new_rev = uinfop->cui_rev; -	}  	kpreempt_enable();  }  #endif /* __xpv */ +static void +ucode_read_rev_amd(cpu_ucode_info_t *uinfop) +{ +	uinfop->cui_rev = rdmsr(MSR_AMD_PATCHLEVEL); +}  static void -ucode_read_rev(struct cpu_ucode_info *uinfop) +ucode_read_rev_intel(cpu_ucode_info_t *uinfop)  {  	struct cpuid_regs crs; @@ -480,6 +791,113 @@ ucode_read_rev(struct cpu_ucode_info *uinfop)  	uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT);  } +static ucode_errno_t +ucode_extract_amd(ucode_update_t *uusp, uint8_t *ucodep, int size) +{ +	uint32_t *ptr = (uint32_t *)ucodep; +	ucode_eqtbl_amd_t *eqtbl; +	ucode_file_amd_t *ufp; +	int count, eq_sig; + +	/* skip over magic number & equivalence table header */ +	ptr += 2; size -= 8; + +	count = *ptr++; size -= 4; +	for (eqtbl = (ucode_eqtbl_amd_t *)ptr; +	    eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != uusp->sig; +	    eqtbl++) +		; + +	eq_sig = eqtbl->ue_equiv_cpu; +	eq_sig = ((eq_sig >> 8) & 0xff00) | (eq_sig & 0xff); + +	/* No equivalent CPU id found, assume outdated microcode file. */ +	if (eq_sig == 0) +		return (EM_HIGHERREV); + +	/* Use the first microcode patch that matches. */ +	do { +		ptr += count >> 2; size -= count; + +		if (!size) +			return (EM_NOMATCH); + +		ptr++; size -= 4; +		count = *ptr++; size -= 4; +		ufp = (ucode_file_amd_t *)ptr; +	} while (ucode_match_amd(eq_sig, &uusp->info, ufp, count) != EM_OK); + +	uusp->ucodep = (uint8_t *)ufp; +	uusp->usize = count; +	uusp->expected_rev = ufp->uf_header.uh_patch_id; + +	return (EM_OK); +} + +static ucode_errno_t +ucode_extract_intel(ucode_update_t *uusp, uint8_t *ucodep, int size) +{ +	uint32_t	header_size = UCODE_HEADER_SIZE_INTEL; +	int		remaining; +	int		found = 0; +	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */ + +	/* +	 * Go through the whole buffer in case there are +	 * multiple versions of matching microcode for this +	 * processor. +	 */ +	for (remaining = size; remaining > 0; ) { +		int	total_size, body_size, ext_size; +		uint8_t	*curbuf = &ucodep[size - remaining]; +		ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf; +		ucode_ext_table_intel_t *uetp = NULL; +		ucode_errno_t tmprc; + +		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); +		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); +		ext_size = total_size - (header_size + body_size); + +		if (ext_size > 0) +			uetp = (ucode_ext_table_intel_t *) +			    &curbuf[header_size + body_size]; + +		tmprc = ucode_match_intel(uusp->sig, &uusp->info, uhp, uetp); + +		/* +		 * Since we are searching through a big file +		 * containing microcode for pretty much all the +		 * processors, we are bound to get EM_NOMATCH +		 * at one point.  However, if we return +		 * EM_NOMATCH to users, it will really confuse +		 * them.  Therefore, if we ever find a match of +		 * a lower rev, we will set return code to +		 * EM_HIGHERREV. +		 */ +		if (tmprc == EM_HIGHERREV) +			search_rc = EM_HIGHERREV; + +		if (tmprc == EM_OK && +		    uusp->expected_rev < uhp->uh_rev) { +#ifndef __xpv +			uusp->ucodep = (uint8_t *)&curbuf[header_size]; +#else +			uusp->ucodep = (uint8_t *)curbuf; +#endif +			uusp->usize = +			    UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); +			uusp->expected_rev = uhp->uh_rev; +			found = 1; +		} + +		remaining -= total_size; +	} + +	if (!found) +		return (search_rc); + +	return (EM_OK); +}  /*   * Entry point to microcode update from the ucode_drv driver.   * @@ -488,32 +906,27 @@ ucode_read_rev(struct cpu_ucode_info *uinfop)  ucode_errno_t  ucode_update(uint8_t *ucodep, int size)  { -	uint32_t	header_size = UCODE_HEADER_SIZE; -	int		remaining;  	int		found = 0;  	processorid_t	id; -	struct ucode_update_struct cached = { 0 }; -	struct ucode_update_struct *cachedp = NULL; +	ucode_update_t	cached = { 0 }; +	ucode_update_t	*cachedp = NULL;  	ucode_errno_t	rc = EM_OK;  	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */  	cpuset_t cpuset; -#ifdef	__xpv -	uint8_t *ustart; -	uint32_t usize; -#endif +	ASSERT(ucode);  	ASSERT(ucodep);  	CPUSET_ZERO(cpuset); -	if (!ucode_capable(CPU)) +	if (!ucode->capable(CPU))  		return (EM_NOTSUP);  	mutex_enter(&cpu_lock);  	for (id = 0; id < max_ncpus; id++) {  		cpu_t *cpu; -		struct ucode_update_struct uus = { 0 }; -		struct ucode_update_struct *uusp = &uus; +		ucode_update_t uus = { 0 }; +		ucode_update_t *uusp = &uus;  		/*  		 * If there is no such CPU or it is not xcall ready, skip it. @@ -542,61 +955,11 @@ ucode_update(uint8_t *ucodep, int size)  			 * the other threads in an HT processor can update  			 * the cpu_ucode_info structure in machcpu.  			 */ -		} else { -			/* -			 * Go through the whole buffer in case there are -			 * multiple versions of matching microcode for this -			 * processor. -			 */ -			for (remaining = size; remaining > 0; ) { -				int	total_size, body_size, ext_size; -				uint8_t	*curbuf = &ucodep[size - remaining]; -				ucode_header_t	*uhp = (ucode_header_t *)curbuf; -				ucode_ext_table_t *uetp = NULL; -				ucode_errno_t tmprc; - -				total_size = -				    UCODE_TOTAL_SIZE(uhp->uh_total_size); -				body_size = UCODE_BODY_SIZE(uhp->uh_body_size); -				ext_size = total_size - -				    (header_size + body_size); - -				if (ext_size > 0) -					uetp = (ucode_ext_table_t *) -					    &curbuf[header_size + body_size]; - -				tmprc = ucode_match(uusp->sig, &uusp->info, -				    uhp, uetp); - -				/* -				 * Since we are searching through a big file -				 * containing microcode for pretty much all the -				 * processors, we are bound to get EM_NOMATCH -				 * at one point.  However, if we return -				 * EM_NOMATCH to users, it will really confuse -				 * them.  Therefore, if we ever find a match of -				 * a lower rev, we will set return code to -				 * EM_HIGHERREV. -				 */ -				if (tmprc == EM_HIGHERREV) -					search_rc = EM_HIGHERREV; - -				if (tmprc == EM_OK && -				    uusp->expected_rev < uhp->uh_rev) { -					uusp->ucodep = &curbuf[header_size]; -#ifdef	__xpv -					ustart = (uint8_t *)curbuf; -					usize = UCODE_TOTAL_SIZE( -					    uhp->uh_total_size); -#endif -					uusp->expected_rev = uhp->uh_rev; -					bcopy(uusp, &cached, sizeof (cached)); -					cachedp = &cached; -					found = 1; -				} - -				remaining -= total_size; -			} +		} else if ((search_rc = ucode->extract(uusp, ucodep, size)) +		    == EM_OK) { +			bcopy(uusp, &cached, sizeof (cached)); +			cachedp = &cached; +			found = 1;  		}  		/* Nothing to do */ @@ -612,7 +975,7 @@ ucode_update(uint8_t *ucodep, int size)  		 * completed.  		 */  		if (id == 0) { -			ucode_update_xpv(uusp, ustart, usize); +			ucode_load_xpv(uusp);  		}  #endif @@ -651,15 +1014,9 @@ ucode_update(uint8_t *ucodep, int size)  void  ucode_check(cpu_t *cp)  { -	struct cpu_ucode_info *uinfop; +	cpu_ucode_info_t *uinfop;  	ucode_errno_t rc = EM_OK; -#ifdef	__xpv -	uint32_t ext_offset; -	uint32_t body_size; -	uint32_t ext_size; -	uint8_t *ustart; -	uint32_t usize; -#endif +	uint32_t new_rev = 0;  	ASSERT(cp);  	if (cp->cpu_id == 0) @@ -668,19 +1025,33 @@ ucode_check(cpu_t *cp)  	uinfop = cp->cpu_m.mcpu_ucode_info;  	ASSERT(uinfop); -	if (!ucode_capable(cp)) +	/* set up function pointers if not already done */ +	if (!ucode) +		switch (cpuid_getvendor(cp)) { +		case X86_VENDOR_AMD: +			ucode = &ucode_amd; +			break; +		case X86_VENDOR_Intel: +			ucode = &ucode_intel; +			break; +		default: +			return; +		} + +	if (!ucode->capable(cp))  		return;  	/*  	 * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon  	 * (Family 6, model 5 and above) and all processors after.  	 */ -	if ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6)) { +	if ((cpuid_getvendor(cp) == X86_VENDOR_Intel) && +	    ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6))) {  		uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >>  		    INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK);  	} -	ucode_read_rev(uinfop); +	ucode->read_rev(uinfop);  #ifdef	__xpv  	/* @@ -695,38 +1066,12 @@ ucode_check(cpu_t *cp)  	/*  	 * Check to see if we need ucode update  	 */ -	if ((rc = ucode_locate(cp, uinfop, &ucodefile)) == EM_OK) { -#ifndef	__xpv -		ucode_update_intel(ucodefile.uf_body, uinfop); -#else -		/* -		 * the hypervisor wants the header, data, and extended -		 * signature tables. We can only get here from the boot -		 * CPU (cpu #0), so use BOP_ALLOC. Since we're using BOP_ALLOC, -		 * We don't need to free. -		 */ -		usize = UCODE_TOTAL_SIZE(ucodefile.uf_header.uh_total_size); -		ustart = (uint8_t *)BOP_ALLOC(bootops, NULL, usize, -		    MMU_PAGESIZE); - -		body_size = UCODE_BODY_SIZE(ucodefile.uf_header.uh_body_size); -		ext_offset = body_size + UCODE_HEADER_SIZE; -		ext_size = usize - ext_offset; -		ASSERT(ext_size >= 0); - -		(void) memcpy(ustart, &ucodefile.uf_header, UCODE_HEADER_SIZE); -		(void) memcpy(&ustart[UCODE_HEADER_SIZE], ucodefile.uf_body, -		    body_size); -		if (ext_size > 0) { -			(void) memcpy(&ustart[ext_offset], -			    ucodefile.uf_ext_table, ext_size); -		} -		ucode_update_xpv(NULL, ustart, usize); -#endif +	if ((rc = ucode->locate(cp, uinfop, &ucodefile)) == EM_OK) { +		new_rev = ucode->load(&ucodefile, uinfop, cp); -		if (uinfop->cui_rev != ucodefile.uf_header.uh_rev) +		if (uinfop->cui_rev != new_rev)  			cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id, -			    uinfop->cui_rev, ucodefile.uf_header.uh_rev); +			    uinfop->cui_rev, new_rev);  	}  	/* @@ -740,7 +1085,7 @@ ucode_check(cpu_t *cp)  	 * of the CPUs in start_other_cpus().  	 */  	if (rc != EM_OK || cp->cpu_id == 0) -		ucode_file_reset(&ucodefile, cp->cpu_id); +		ucode->file_reset(&ucodefile, cp->cpu_id);  }  /* @@ -751,9 +1096,10 @@ ucode_get_rev(uint32_t *revp)  {  	int i; +	ASSERT(ucode);  	ASSERT(revp); -	if (!ucode_capable(CPU)) +	if (!ucode->capable(CPU))  		return (EM_NOTSUP);  	mutex_enter(&cpu_lock); diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c index 55e1d85f6e..10492414be 100644 --- a/usr/src/uts/i86pc/os/mp_startup.c +++ b/usr/src/uts/i86pc/os/mp_startup.c @@ -1396,7 +1396,7 @@ start_other_cpus(int cprboot)  	}  	/* Free the space allocated to hold the microcode file */ -	ucode_free(); +	ucode_cleanup();  	affinity_clear(); diff --git a/usr/src/uts/intel/io/ucode_drv.c b/usr/src/uts/intel/io/ucode_drv.c index d71b0bcbe5..6a63bba8a9 100644 --- a/usr/src/uts/intel/io/ucode_drv.c +++ b/usr/src/uts/intel/io/ucode_drv.c @@ -138,6 +138,12 @@ ucode_open(dev_t *dev, int flag, int otyp, cred_t *cr)  static int  ucode_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)  { +	/* +	 * Make sure that the ucode ops pointer has been set up. +	 */ +	if (!ucode) +		return (EIO); +  	switch (cmd) {  	case UCODE_GET_VERSION: {  		int size; @@ -218,7 +224,7 @@ ucode_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)  			return (EFAULT);  		} -		if ((rc = ucode_validate(ucodep, size)) != EM_OK) { +		if ((rc = ucode->validate(ucodep, size)) != EM_OK) {  			kmem_free(ucodep, size);  			STRUCT_FSET(h, uw_errno, rc);  			if (ddi_copyout(STRUCT_BUF(h), (void *)arg, diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h index 23e04d3286..dc8ec9c8c5 100644 --- a/usr/src/uts/intel/sys/controlregs.h +++ b/usr/src/uts/intel/sys/controlregs.h @@ -26,8 +26,6 @@  #ifndef	_SYS_CONTROLREGS_H  #define	_SYS_CONTROLREGS_H -#pragma ident	"%Z%%M%	%I%	%E% SMI" -  #ifndef _ASM  #include <sys/types.h>  #endif @@ -224,8 +222,9 @@ extern "C" {   */  #define	AMD_GH_NB_CFG_EN_ECS		(UINT64_C(1) << 46) -/* AMD */ +/* AMD microcode patch loader */  #define	MSR_AMD_PATCHLEVEL	0x8b +#define	MSR_AMD_PATCHLOADER	0xc0010020  #ifdef __cplusplus  } diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h index ba8cbf15ea..89f07ce6cc 100644 --- a/usr/src/uts/intel/sys/x86_archext.h +++ b/usr/src/uts/intel/sys/x86_archext.h @@ -608,7 +608,7 @@ struct cpu_ucode_info;  extern void ucode_alloc_space(struct cpu *);  extern void ucode_free_space(struct cpu *);  extern void ucode_check(struct cpu *); -extern void ucode_free(); +extern void ucode_cleanup();  #if !defined(__xpv)  extern	char _tsc_mfence_start; | 
