|
| 1 | +from dataclasses import dataclass |
| 2 | + |
| 3 | +from lib.host import Host |
| 4 | + |
| 5 | +NO_SUBLEAF = 0xffffffff |
| 6 | + |
| 7 | +@dataclass(frozen=True) |
| 8 | +class CpuidRegisters: |
| 9 | + eax: int |
| 10 | + ebx: int |
| 11 | + ecx: int |
| 12 | + edx: int |
| 13 | + |
| 14 | +class CpuPolicy: |
| 15 | + """A specific CPU policy (PV, HVM, ...)""" |
| 16 | + # (leaf, subleaf) -> (eax, ebx, ecx, edx) |
| 17 | + cpuid: dict[tuple[int, int], CpuidRegisters] |
| 18 | + # msr -> val |
| 19 | + msr: dict[int, int] |
| 20 | + |
| 21 | + def __init__(self, cpuid: dict[tuple[int, int], CpuidRegisters], msr: dict[int, int]): |
| 22 | + self.cpuid = cpuid |
| 23 | + self.msr = msr |
| 24 | + |
| 25 | +class HostCpuPolicy: |
| 26 | + """All CPU policies of a host (CPUID, specific MSRs)""" |
| 27 | + policies: dict[str, CpuPolicy] = {} |
| 28 | + |
| 29 | + def __init__(self, host: Host): |
| 30 | + text = host.ssh("xen-cpuid --policy") |
| 31 | + current_policy: CpuPolicy | None = None |
| 32 | + mode: Literal["cpuid", "msr"] | None = None |
| 33 | + |
| 34 | + lines = text.splitlines() |
| 35 | + |
| 36 | + for line in lines: |
| 37 | + line = line.rstrip() |
| 38 | + |
| 39 | + # ---- Policy header ---- |
| 40 | + if "policy:" in line: |
| 41 | + # Example: "Raw policy: 32 leaves, 2 MSRs" |
| 42 | + name, rest = line.split("policy:", 1) |
| 43 | + name = name.strip() |
| 44 | + |
| 45 | + self.policies[name] = CpuPolicy(dict(), dict()) |
| 46 | + current_policy = self.policies[name] |
| 47 | + mode = None |
| 48 | + continue |
| 49 | + |
| 50 | + if current_policy is None: |
| 51 | + continue |
| 52 | + |
| 53 | + # ---- Section switches ---- |
| 54 | + if line.strip() == "CPUID:": |
| 55 | + mode = "cpuid" |
| 56 | + continue |
| 57 | + |
| 58 | + if line.strip() == "MSRs:": |
| 59 | + mode = "msr" |
| 60 | + continue |
| 61 | + |
| 62 | + # Skip table headers |
| 63 | + if "leaf" in line or "index" in line or not line.strip(): |
| 64 | + continue |
| 65 | + |
| 66 | + # ---- CPUID parsing ---- |
| 67 | + if mode == "cpuid": |
| 68 | + # Example: |
| 69 | + # 00000004:00000003 -> 1c03c163:02c0003f:00001fff:00000006 |
| 70 | + left, right = line.split("->") |
| 71 | + leaf_hex, subleaf_hex = left.strip().split(":") |
| 72 | + eax, ebx, ecx, edx = right.strip().split(":") |
| 73 | + |
| 74 | + key = (int(leaf_hex, 16), int(subleaf_hex, 16)) |
| 75 | + current_policy.cpuid[key] = CpuidRegisters( |
| 76 | + int(eax, 16), |
| 77 | + int(ebx, 16), |
| 78 | + int(ecx, 16), |
| 79 | + int(edx, 16) |
| 80 | + ) |
| 81 | + continue |
| 82 | + |
| 83 | + # ---- MSR parsing ---- |
| 84 | + if mode == "msr": |
| 85 | + # Example: |
| 86 | + # 0000010a -> 400000000c000000 |
| 87 | + idx_hex, val_hex = line.split("->") |
| 88 | + idx = int(idx_hex.strip(), 16) |
| 89 | + val = int(val_hex.strip(), 16) |
| 90 | + current_policy.msr[idx] = val |
| 91 | + continue |
0 commit comments