]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tools/x86/kcpuid: Parse subleaf ranges if provided
authorAhmed S. Darwish <darwi@linutronix.de>
Thu, 18 Jul 2024 13:47:47 +0000 (15:47 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Fri, 2 Aug 2024 07:17:19 +0000 (09:17 +0200)
It's a common pattern in cpuid leaves to have the same bitfields format
repeated across a number of subleaves.  Typically, this is used for
enumerating hierarchial structures like cache and TLB levels, CPU
topology levels, etc.

Modify kcpuid.c to handle subleaf ranges in the CSV file subleaves
column.  For example, make it able to parse lines in the form:

 # LEAF, SUBLEAVES,  reg,    bits,    short_name             , ...
    0xb,       1:0,  eax,     4:0,    x2apic_id_shift        , ...
    0xb,       1:0,  ebx,    15:0,    domain_lcpus_count     , ...
    0xb,       1:0,  ecx,     7:0,    domain_nr              , ...

This way, full output can be printed to the user.

Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20240718134755.378115-8-darwi@linutronix.de
tools/arch/x86/kcpuid/kcpuid.c

index 725a7a27fcac8f90bfcf2220a3405b3c8a737441..1b25c0a95d3f9adc61ee32517c65ff486bf3140a 100644 (file)
@@ -305,6 +305,8 @@ static int parse_line(char *line)
        struct bits_desc *bdesc;
        int reg_index;
        char *start, *end;
+       u32 subleaf_start, subleaf_end;
+       unsigned bit_start, bit_end;
 
        /* Skip comments and NULL line */
        if (line[0] == '#' || line[0] == '\n')
@@ -343,13 +345,25 @@ static int parse_line(char *line)
                return 0;
 
        /* subleaf */
-       sub = strtoul(tokens[1], NULL, 0);
-       if ((int)sub > func->nr)
-               return -1;
+       buf = tokens[1];
+       end = strtok(buf, ":");
+       start = strtok(NULL, ":");
+       subleaf_end = strtoul(end, NULL, 0);
+
+       /* A subleaf range is given? */
+       if (start) {
+               subleaf_start = strtoul(start, NULL, 0);
+               subleaf_end = min(subleaf_end, (u32)(func->nr - 1));
+               if (subleaf_start > subleaf_end)
+                       return 0;
+       } else {
+               subleaf_start = subleaf_end;
+               if (subleaf_start > (u32)(func->nr - 1))
+                       return 0;
+       }
 
-       leaf = &func->leafs[sub];
+       /* register */
        buf = tokens[2];
-
        if (strcasestr(buf, "EAX"))
                reg_index = R_EAX;
        else if (strcasestr(buf, "EBX"))
@@ -361,23 +375,23 @@ static int parse_line(char *line)
        else
                goto err_exit;
 
-       reg = &leaf->info[reg_index];
-       bdesc = &reg->descs[reg->nr++];
-
        /* bit flag or bits field */
        buf = tokens[3];
-
        end = strtok(buf, ":");
-       bdesc->end = strtoul(end, NULL, 0);
-       bdesc->start = bdesc->end;
-
-       /* start != NULL means it is bit fields */
        start = strtok(NULL, ":");
-       if (start)
-               bdesc->start = strtoul(start, NULL, 0);
-
-       strcpy(bdesc->simp, strtok(tokens[4], " \t"));
-       strcpy(bdesc->detail, tokens[5]);
+       bit_end = strtoul(end, NULL, 0);
+       bit_start = (start) ? strtoul(start, NULL, 0) : bit_end;
+
+       for (sub = subleaf_start; sub <= subleaf_end; sub++) {
+               leaf = &func->leafs[sub];
+               reg = &leaf->info[reg_index];
+               bdesc = &reg->descs[reg->nr++];
+
+               bdesc->end = bit_end;
+               bdesc->start = bit_start;
+               strcpy(bdesc->simp, strtok(tokens[4], " \t"));
+               strcpy(bdesc->detail, tokens[5]);
+       }
        return 0;
 
 err_exit: