|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH V2] x86, amd_ucode: Support multiple container files appended together
On 6/24/2014 2:23 AM, Jan Beulich wrote: --- a/xen/arch/x86/microcode_amd.c +++ b/xen/arch/x86/microcode_amd.c @@ -29,6 +29,17 @@#define pr_debug(x...) ((void)0) +#define CONT_HDR_SIZE 12+#define SECTION_HDR_SIZE 8 +#define AMD_UCODE_APPLY_SUCCESS 0 +/* + * Currently, there are two AMD container files on + * https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/tree/amd-ucode + * So, this is max number of container binaries that can be appended + * together and packaged along with initrd. + */ +#define AMD_MAX_CONT_APPEND 2So as soon as a 3rd one appears the code will need to be changed again? Pretty bad approach I would say. Yeah. I thought about it too. But if a new container comes up, then it will still take very little effort to change this macro here. The idea was that I could use this for catching the corner case.Anyway, I have got a different way to handle that. (so this macro def will go as a result) (explanation below...)
Fixed this. @@ -211,7 +235,7 @@ static int apply_microcode(int cpu)uci->cpu_sig.rev = rev; - return 0;+ return AMD_UCODE_APPLY_SUCCESS;Definitely not: This function _has to_ return zero (due to its use in the initializer of microcode_amd_ops), i.e. someone altering the definition of AMD_UCODE_APPLY_SUCCESS (e.g. making it a boolean) would break things. So, the main reason behind introducing this macro was that-For single containers, in cases of success, the last value assigned for 'error' is from 'apply_microcode' (above). And unless there is a 'save_error', this is the value returned.I wanted to make it clear that we are returning this value for multiple containers too (on success) I understand your concern, So I have changed it to return 0.
Would this be better? - if ( *(const uint32_t *)buf != UCODE_MAGIC )I can still let the above comment be there (or modify it to make it more clear?) @@ -272,14 +304,13 @@ static int get_ucode_from_buffer_amd(static int install_equiv_cpu_table( No. Have fixed this.
For single containers, this check made some sense earlier as we verify to see there is *some* data beyond the equivalent_table structure.Say, mpbuf->len=0 and we return error val; Due to the fact that we have already advanced *offset, cases when we reach EOF or *offset goes over bufsize is handled in container_fast_forward function.For multiple containers, we will always have at least two such container headers and hence, mpbuf->len + 12 is always less than total_sizeIf first container for some reason is corrupted and exposes mpbuf->len=0, we return EINVAL and forward to next container. (This is infact one reason to advance *offset earlier. See below) Now, if the last container were to have mpbuf->len=0, As Boris mentioned on earlier thread, we will continue because 'if (0+12 >= tot_size) ' is false. Here too, we will return EINVAL. Again, advancing *offset early allows to workaround these issues. And this check can be removed as a result. + *curr_offset += mpbuf->len + CONT_HDR_SIZE; /* add header length */if ( mpbuf->type != UCODE_EQUIV_CPU_TABLE_TYPE ) So, If for some reason this function returns error val for the _first_ container; Then *offset would still be 0.And 'container_fast_forward' will not advance it as both 'MAGIC' and 'UCODE_EQUIV_CPU_TABLE_TYPE' checks match. We will be stuck in this loop. Hence, I moved the assignment up. But, this is also introducing some issues that I failed to handle here. Have fixed it now. (See below)
Ok. I have removed this cast (and as a consequence *header) entirely. Also need - if ( size_left < 0 ) check. Reason- With offset value being advanced aggressively in 'install_equiv_cpu_table', It could be that we go over the bufsize. This situation will be caught here. + if ( header[0] == UCODE_MAGIC && + header[1] == UCODE_EQUIV_CPU_TABLE_TYPE )Are these two valid if size_left < SECTION_HDR_SIZE? Fixed this. + break; + + size = header[1] + SECTION_HDR_SIZE; + *offset += size; + + if ( size_left >= size ) + size_left -= size; + }And if size_left < size we're continuing the loop (perhaps indefinitely)? Fixed this.Instead of above check, I inverted the relation and saved an indentation level.
Have modified this to while ( offset < bufsize )
This is because there can be only one container that has the valid patch. Further I again don't follow the conditions you use: containers_processed >= AMD_MAX_CONT_APPEND should have got dealt with (if at all possible) much earlier (after the first loop), and the "&& error" looks superfluous as long as AMD_UCODE_APPLY_SUCCESS == 0. Which finally gets us back to the same point made above - this function again has to return zero on success, no matter what AMD_UCODE_APPLY_SUCCESS is defined to. Ok, I have removed AMD_MAX_CONT_APPEND altogether now, and changed it to- if ( offset < bufsize ) error = 0;From the loop: while ( (error = get_ucode_from_buffer_amd(mc_amd, buf, bufsize,&offset)) == 0 ) we will always have (offset == bufsize) if the patch happens to be on the last container file (even as apply_microcode succeeds) So, the modified check should work fine. While at the same time does not change behavior of single container files.
Btw, we also need a similar check here:
if ( save_error )
{
if ( (error != save_error) && (offset < bufsize) ) {
error = 0;
}
xfree(mc_amd);
uci->mc.mc_amd = mc_old;
}
Reason:
By the time 'microcode_init' runs, we have already updated the patch
level on all (currently) running cpus.
So, get_ucode_from_buffer_amd will return -EINVAL due to - if ( mpbuf->type != UCODE_UCODE_TYPE ) Only this time, there is no 'applied_offset' as well. So, 'save_error' = 1. But error == -EINVAL.This situation can only occur in the case of multiple container files and only when update succeeded with the first container file itself. Hence, this check is also necessary to return 0 for success. I'll await your comments before sending out a V3. Thanks, -Aravind. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |