[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] x86, amd_ucode: Support multiple container files appended together
On 6/20/2014 10:57 AM, Boris Ostrovsky wrote: On 06/19/2014 11:14 AM, Aravind Gopalakrishnan wrote:This patch adds support for parsing through multiple AMD containerbinaries concatenated together. It is a feature already present in Linux.Link to linux patch:http://lkml.kernel.org/r/1370463236-2115-3-git-send-email-jacob.shin@xxxxxxxWhile at it, define HDR_SIZES and use these for clarity. Signed-off-by: Aravind Gopalakrishnan <aravind.gopalakrishnan@xxxxxxx> Reviewed-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@xxxxxxx> ---xen/arch/x86/microcode_amd.c | 120 ++++++++++++++++++++++++++++++++++++------1 file changed, 103 insertions(+), 17 deletions(-) diff --git a/xen/arch/x86/microcode_amd.c b/xen/arch/x86/microcode_amd.c index e83f4b6..6478dda 100644 --- a/xen/arch/x86/microcode_amd.c +++ b/xen/arch/x86/microcode_amd.c @@ -29,6 +29,9 @@ #define pr_debug(x...) ((void)0) +#define CONT_HDR_SIZE 12 +#define SECTION_HDR_SIZE 8 + struct __packed equiv_cpu_entry { uint32_t installed_cpu; uint32_t fixed_errata_mask;@@ -124,6 +127,25 @@ static bool_t verify_patch_size(uint32_t patch_size)return (patch_size <= max_size); }+static void find_equiv_cpu_id(const struct equiv_cpu_entry *equiv_cpu_table,+ unsigned int current_cpu_id, + unsigned int *equiv_cpu_id) +{ + unsigned int i; + + if ( !equiv_cpu_table ) + return; + + for ( i = 0; equiv_cpu_table[i].installed_cpu != 0; i++ ) + { + if ( current_cpu_id == equiv_cpu_table[i].installed_cpu ) + { + *equiv_cpu_id = equiv_cpu_table[i].equiv_cpu & 0xffff; + break; + } + } +} +static bool_t microcode_fits(const struct microcode_amd *mc_amd, int cpu){ struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);@@ -131,21 +153,13 @@ static bool_t microcode_fits(const struct microcode_amd *mc_amd, int cpu) const struct equiv_cpu_entry *equiv_cpu_table = mc_amd->equiv_cpu_table;unsigned int current_cpu_id; unsigned int equiv_cpu_id = 0x0; - unsigned int i; /* We should bind the task to the CPU */ BUG_ON(cpu != raw_smp_processor_id()); current_cpu_id = cpuid_eax(0x00000001); - for ( i = 0; equiv_cpu_table[i].installed_cpu != 0; i++ ) - { - if ( current_cpu_id == equiv_cpu_table[i].installed_cpu ) - { - equiv_cpu_id = equiv_cpu_table[i].equiv_cpu & 0xffff; - break; - } - } + find_equiv_cpu_id(equiv_cpu_table, current_cpu_id, &equiv_cpu_id); if ( !equiv_cpu_id ) return 0; @@ -236,7 +250,15 @@ static int get_ucode_from_buffer_amd( mpbuf = (const struct mpbhdr *)&bufp[off]; if ( mpbuf->type != UCODE_UCODE_TYPE ) {- printk(KERN_ERR "microcode: Wrong microcode payload type field\n");+ /* + * We will hit this condition only if an update has succeeded + * but there is still another container file being parsed. + * In that case, there is no need of this ERR message to be + * printed. + */ + if ( mpbuf->type != UCODE_MAGIC )+ printk(KERN_ERR "microcode: Wrong microcode payload type field\n");+ return -EINVAL; } @@ -260,7 +282,7 @@ static int get_ucode_from_buffer_amd( } memcpy(mc_amd->mpb, mpbuf->data, mpbuf->len); - *offset = off + mpbuf->len + 8; + *offset = off + mpbuf->len + SECTION_HDR_SIZE;pr_debug("microcode: CPU%d size %zu, block size %u offset %zu equivID %#x rev %#x\n",raw_smp_processor_id(), bufsize, mpbuf->len, off, @@ -272,13 +294,16 @@ static int get_ucode_from_buffer_amd( static int install_equiv_cpu_table( struct microcode_amd *mc_amd, - const uint32_t *buf, - size_t *offset) + const uint8_t *data, + size_t *tot_size,Why is this a pointer? This routine does not modify the value. Yeah. No point. I'll fix it. Thanks for the pointer :) + size_t *curr_offset) { + size_t off = *curr_offset; + uint32_t *buf = (uint32_t *) &data[off]; const struct mpbhdr *mpbuf = (const struct mpbhdr *)&buf[1]; /* No more data */ - if ( mpbuf->len + 12 >= *offset ) + if ( mpbuf->len + CONT_HDR_SIZE >= *tot_size ) return -EINVAL; if ( mpbuf->type != UCODE_EQUIV_CPU_TABLE_TYPE ) @@ -303,7 +328,32 @@ static int install_equiv_cpu_table( memcpy(mc_amd->equiv_cpu_table, mpbuf->data, mpbuf->len); mc_amd->equiv_cpu_table_size = mpbuf->len; - *offset = mpbuf->len + 12; /* add header length */+ *curr_offset += mpbuf->len + CONT_HDR_SIZE; /* add header length */+ + return 0; +} ++static int container_fast_forward(const uint8_t *data, size_t size_left, size_t *offset)+{ + size_t size, off; + uint32_t *header; + + while ( size_left ) + { + off = *offset; + header = (uint32_t *) &data[off]; + if ( header[0] == UCODE_MAGIC && + header[1] == UCODE_EQUIV_CPU_TABLE_TYPE ) + break; + + size = header[1] + SECTION_HDR_SIZE; + *offset += size; + size_left -= size; + + } + + if ( !size_left ) + return -EINVAL; return 0; } @@ -311,14 +361,19 @@ static int install_equiv_cpu_table(static int cpu_request_microcode(int cpu, const void *buf, size_t bufsize){ struct microcode_amd *mc_amd, *mc_old; - size_t offset = bufsize; + size_t offset = 0; + size_t tot_size = bufsize; size_t last_offset, applied_offset = 0; int error = 0, save_error = 1; struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); + unsigned int current_cpu_id; + unsigned int equiv_cpu_id = 0x0; /* We should bind the task to the CPU */ BUG_ON(cpu != raw_smp_processor_id()); + current_cpu_id = cpuid_eax(0x00000001); + if ( *(const uint32_t *)buf != UCODE_MAGIC ) {printk(KERN_ERR "microcode: Wrong microcode patch file magic\n"); @@ -334,7 +389,30 @@ static int cpu_request_microcode(int cpu, const void *buf, size_t bufsize)goto out; } - error = install_equiv_cpu_table(mc_amd, buf, &offset); + /* + * Multiple container file support: + * 1. check if this container file has equiv_cpu_id match + * 2. If not, fast-fwd to next container file + */ + while ( (error = install_equiv_cpu_table(mc_amd, buf, &tot_size, + &offset)) == 0 )install_equiv_cpu_table() checks whether container size is larger than the buffer size. Not really.It is basically checking if we have data at all to parse (like the comment says:/* No more data */) If we have multiple containers merged I think tot_size is the size of the merged file, not of an individual container. That's right. And this makes the first check in install_equiv_cpu_table() not especially meaningful. Theoretically-If it so happens that we don't have any patch files and just the container header, then mpbuf->len would be zero and if ( mpbuf->len + CONT_HDR_SIZE >= *tot_size ) will fail in this case- (which gives some meaning to the check being there)1. If containers are concatenated, but there is no matching patch on the first one 2. So, we fast-fwd to next container file but this one has mpbuf->len=0 Which leads me to another scenario though-1. If we do have multiple containers and if right patch is not on the first one, but on some subsequent container 2. If the first container has mpbuf->len=0Then we'd just error out right there. Hmm.. I'll have to re-work the logic then. Come to think, if the first container is corrupted for some reason and returns error (or there's an -ENOMEM), then we are going to return pre-maturely Instead, we should probably (try to) forward to next container and look for patches there as well. Shall fix this logic in a v2.. Thanks, -Aravind _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |