diff --git a/qemu/include/qemu/bitops.h b/qemu/include/qemu/bitops.h index c7587b0b..0bbffd4a 100644 --- a/qemu/include/qemu/bitops.h +++ b/qemu/include/qemu/bitops.h @@ -136,6 +136,16 @@ static inline int test_bit(long nr, const unsigned long *addr) return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); } +/** + * find_last_bit - find the last set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit number of the first set bit, or size. + */ +unsigned long find_last_bit(const unsigned long *addr, + unsigned long size); + /** * find_next_bit - find the next set bit in a memory region * @addr: The address to base the search on diff --git a/qemu/target/i386/cpu.c b/qemu/target/i386/cpu.c index 606cd9e7..5130a351 100644 --- a/qemu/target/i386/cpu.c +++ b/qemu/target/i386/cpu.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/bitops.h" #include "unicorn/platform.h" #include "uc_priv.h" @@ -461,6 +462,8 @@ static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu, uint32_t *ecx, uint32_t *edx) { struct core_topology topo = {0}; + unsigned long nodes; + int shift; build_core_topology(cs->nr_cores, cpu->core_id, &topo); *eax = cpu->apic_id; @@ -493,7 +496,28 @@ static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu, * 2 Socket id * 1:0 Node id */ - *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) | topo.node_id; + if (topo.num_nodes <= 4) { + *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) | + topo.node_id; + } else { + /* + * Node id fix up. Actual hardware supports up to 4 nodes. But with + * more than 32 cores, we may end up with more than 4 nodes. + * Node id is a combination of socket id and node id. Only requirement + * here is that this number should be unique accross the system. + * Shift the socket id to accommodate more nodes. We dont expect both + * socket id and node id to be big number at the same time. This is not + * an ideal config but we need to to support it. Max nodes we can have + * is 32 (255/8) with 8 cores per node and 255 max cores. We only need + * 5 bits for nodes. Find the left most set bit to represent the total + * number of nodes. find_last_bit returns last set bit(0 based). Left + * shift(+1) the socket id to represent all the nodes. + */ + nodes = topo.num_nodes - 1; + shift = find_last_bit(&nodes, 8); + *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << (shift + 1)) | + topo.node_id; + } *edx = 0; } diff --git a/qemu/util/bitops.c b/qemu/util/bitops.c index 235bcb07..eb24bf04 100644 --- a/qemu/util/bitops.c +++ b/qemu/util/bitops.c @@ -126,3 +126,32 @@ found_first: found_middle: return result + ctzl(~tmp); } + +unsigned long find_last_bit(const unsigned long *addr, unsigned long size) +{ + unsigned long words; + unsigned long tmp; + + /* Start at final word. */ + words = size / BITS_PER_LONG; + + /* Partial final word? */ + if (size & (BITS_PER_LONG-1)) { + tmp = (addr[words] & (~0UL >> (BITS_PER_LONG + - (size & (BITS_PER_LONG-1))))); + if (tmp) { + goto found; + } + } + + while (words) { + tmp = addr[--words]; + if (tmp) { + found: + return words * BITS_PER_LONG + BITS_PER_LONG - 1 - clzl(tmp); + } + } + + /* Not found */ + return size; +}