| git.druid.rocks | index | druid520 | kaboom | src/ | drivers/ | cpu.nsc |
src/drivers/cpu.nsc
/*
* cpu identification via the cpuid instruction (cpu_asm.s). vendor and
* brand strings only -- no feature-flag decoding (leaf 1's edx/ecx
* bits, leaf 7's ebx/ecx/edx, ...), matching this kernel's own "ship
* the real minimal version" pattern; extend if something ever needs a
* specific flag rather than building a whole bitfield table nothing
* reads yet.
*/
void cpuid(u32 leaf, ptr out);
void
cpu_byte_set(ptr base, u64 index, u8 val)
{
u64 wordoff;
u64 byteoff;
u64 word;
wordoff = index & ~(u64)7;
byteoff = index & (u64)7;
word = (u64)*(base + wordoff);
word = word & ~((u64)0xff << (byteoff * (u64)8));
word = word | ((u64)val << (byteoff * (u64)8));
*(base + wordoff) = (i64)word;
}
/* unpacks one cpuid result register (a full zero-extended 8-byte word
* here -- see cpu_asm.s) into 4 ascii bytes at dst[dst_off..+3],
* little-endian (the byte order cpuid's own register-as-string
* convention always uses, for both the vendor and brand strings). */
void
cpu_copy_reg_bytes(ptr dst, u64 dst_off, u64 reg)
{
u64 i;
u8 b;
i = 0;
while(i < (u64)4)
{
b = (u8)((reg >> (i * (u64)8)) & (u64)0xff);
cpu_byte_set(dst, dst_off + i, b);
i = i + (u64)1;
}
}
/* fills buf (room for 13 bytes) with the 12-char vendor id string
* ("GenuineIntel", "AuthenticAMD", "TCGTCGTCGTCG" under plain qemu
* tcg, ...) plus a null terminator. cpuid leaf 0's own well-known
* quirk: the string's bytes come back in ebx,edx,ecx register order,
* not the eax,ebx,ecx,edx order every other multi-register cpuid
* result (including the brand string below) uses. */
global void
cpu_vendor(ptr buf)
{
i8 result[32];
ptr r;
cpuid((u32)0, &result[0]);
r = &result[0];
cpu_copy_reg_bytes(buf, (u64)0, (u64)*(r + 8)); /* ebx */
cpu_copy_reg_bytes(buf, (u64)4, (u64)*(r + 24)); /* edx */
cpu_copy_reg_bytes(buf, (u64)8, (u64)*(r + 16)); /* ecx */
cpu_byte_set(buf, (u64)12, (u8)0);
}
/* fills buf (room for 49 bytes) with the 48-char brand string
* ("Intel(R) Core(TM) ...", often space-padded by the cpu itself)
* plus a null terminator, from cpuid's 3 extended leaves
* (0x80000002-0x80000004), each contributing 16 bytes in normal
* eax,ebx,ecx,edx order. doesn't check leaf 0x80000000's own max-leaf
* return first -- every cpu qemu emulates supports these, and a real
* cpu old enough not to would have failed this kernel's boot far
* earlier for unrelated reasons. */
global void
cpu_brand(ptr buf)
{
i8 result[32];
ptr r;
u64 off;
u32 leaf;
i32 li;
r = &result[0];
off = 0;
li = 0;
while(li < 3)
{
leaf = (u32)(0x80000002 + li);
cpuid(leaf, r);
cpu_copy_reg_bytes(buf, off, (u64)*(r + 0));
off = off + (u64)4;
cpu_copy_reg_bytes(buf, off, (u64)*(r + 8));
off = off + (u64)4;
cpu_copy_reg_bytes(buf, off, (u64)*(r + 16));
off = off + (u64)4;
cpu_copy_reg_bytes(buf, off, (u64)*(r + 24));
off = off + (u64)4;
li = li + 1;
}
cpu_byte_set(buf, off, (u8)0);
}