Skip to main content

vmaware/
memo.rs

1//! Global memoisation layer – mirrors vmaware_memo.c.
2//!
3//! All technique results, brand detections, CPU info and other computed values
4//! are stored here so each expensive check runs at most once per process.
5
6use std::collections::HashMap;
7use std::sync::{Mutex, OnceLock};
8
9use crate::types::{HyperXState, VMBrand};
10
11// ── Per-technique result cache ────────────────────────────────────────────────
12
13#[derive(Debug, Clone)]
14pub struct TechResult {
15    pub result: bool,
16    pub points: u32,
17    pub brand: VMBrand,
18}
19
20static TECH_CACHE: OnceLock<Mutex<HashMap<u8, TechResult>>> = OnceLock::new();
21
22fn tech_cache() -> std::sync::MutexGuard<'static, HashMap<u8, TechResult>> {
23    TECH_CACHE
24        .get_or_init(|| Mutex::new(HashMap::new()))
25        .lock()
26        .unwrap()
27}
28
29/// Store a technique result.
30pub fn cache_store(tech_id: u8, result: bool, points: u32, brand: VMBrand) {
31    tech_cache().insert(tech_id, TechResult { result, points, brand });
32}
33
34/// Fetch a cached technique result, if present.
35pub fn cache_fetch(tech_id: u8) -> Option<TechResult> {
36    tech_cache().get(&tech_id).cloned()
37}
38
39/// Check if a technique result is already cached.
40pub fn is_cached(tech_id: u8) -> bool {
41    tech_cache().contains_key(&tech_id)
42}
43
44// ── Single brand cache ────────────────────────────────────────────────────────
45
46static SINGLE_BRAND: OnceLock<Mutex<Option<VMBrand>>> = OnceLock::new();
47
48fn single_brand_cell() -> std::sync::MutexGuard<'static, Option<VMBrand>> {
49    SINGLE_BRAND.get_or_init(|| Mutex::new(None)).lock().unwrap()
50}
51
52pub fn set_single_brand(b: VMBrand) {
53    *single_brand_cell() = Some(b);
54}
55
56pub fn get_single_brand() -> Option<VMBrand> {
57    *single_brand_cell()
58}
59
60// ── Multiple-brand string cache ───────────────────────────────────────────────
61
62static MULTI_BRAND: OnceLock<Mutex<Option<String>>> = OnceLock::new();
63
64fn multi_brand_cell() -> std::sync::MutexGuard<'static, Option<String>> {
65    MULTI_BRAND.get_or_init(|| Mutex::new(None)).lock().unwrap()
66}
67
68pub fn set_multi_brand(s: String) {
69    *multi_brand_cell() = Some(s);
70}
71
72pub fn get_multi_brand() -> Option<String> {
73    multi_brand_cell().clone()
74}
75
76// ── Brand list cache ──────────────────────────────────────────────────────────
77
78static BRAND_LIST: OnceLock<Mutex<Vec<VMBrand>>> = OnceLock::new();
79
80fn brand_list_cell() -> std::sync::MutexGuard<'static, Vec<VMBrand>> {
81    BRAND_LIST.get_or_init(|| Mutex::new(Vec::new())).lock().unwrap()
82}
83
84pub fn set_brand_list(list: Vec<VMBrand>) {
85    *brand_list_cell() = list;
86}
87
88pub fn get_brand_list() -> Vec<VMBrand> {
89    brand_list_cell().clone()
90}
91
92pub fn brand_list_is_set() -> bool {
93    !brand_list_cell().is_empty()
94}
95
96// ── Conclusion string cache ───────────────────────────────────────────────────
97
98static CONCLUSION: OnceLock<Mutex<Option<String>>> = OnceLock::new();
99
100fn conclusion_cell() -> std::sync::MutexGuard<'static, Option<String>> {
101    CONCLUSION.get_or_init(|| Mutex::new(None)).lock().unwrap()
102}
103
104pub fn set_conclusion(s: String) {
105    *conclusion_cell() = Some(s);
106}
107
108pub fn get_conclusion() -> Option<String> {
109    conclusion_cell().clone()
110}
111
112// ── CPU brand string cache ────────────────────────────────────────────────────
113
114static CPU_BRAND: OnceLock<Mutex<Option<String>>> = OnceLock::new();
115
116fn cpu_brand_cell() -> std::sync::MutexGuard<'static, Option<String>> {
117    CPU_BRAND.get_or_init(|| Mutex::new(None)).lock().unwrap()
118}
119
120pub fn set_cpu_brand(s: String) {
121    *cpu_brand_cell() = Some(s);
122}
123
124pub fn get_cpu_brand() -> Option<String> {
125    cpu_brand_cell().clone()
126}
127
128// ── Thread count cache ────────────────────────────────────────────────────────
129
130static THREAD_COUNT: OnceLock<Mutex<Option<u32>>> = OnceLock::new();
131
132fn thread_count_cell() -> std::sync::MutexGuard<'static, Option<u32>> {
133    THREAD_COUNT.get_or_init(|| Mutex::new(None)).lock().unwrap()
134}
135
136pub fn set_thread_count(n: u32) {
137    *thread_count_cell() = Some(n);
138}
139
140pub fn get_thread_count() -> Option<u32> {
141    *thread_count_cell()
142}
143
144// ── HyperX state cache ────────────────────────────────────────────────────────
145
146static HYPERX_STATE: OnceLock<Mutex<Option<HyperXState>>> = OnceLock::new();
147
148fn hyperx_cell() -> std::sync::MutexGuard<'static, Option<HyperXState>> {
149    HYPERX_STATE.get_or_init(|| Mutex::new(None)).lock().unwrap()
150}
151
152pub fn set_hyperx_state(s: HyperXState) {
153    *hyperx_cell() = Some(s);
154}
155
156pub fn get_hyperx_state() -> Option<HyperXState> {
157    *hyperx_cell()
158}
159
160// ── BIOS info cache ───────────────────────────────────────────────────────────
161
162#[derive(Debug, Clone, Default)]
163pub struct BiosInfo {
164    pub manufacturer: String,
165    pub model: String,
166}
167
168static BIOS_INFO: OnceLock<Mutex<Option<BiosInfo>>> = OnceLock::new();
169
170fn bios_cell() -> std::sync::MutexGuard<'static, Option<BiosInfo>> {
171    BIOS_INFO.get_or_init(|| Mutex::new(None)).lock().unwrap()
172}
173
174pub fn set_bios_info(info: BiosInfo) {
175    *bios_cell() = Some(info);
176}
177
178pub fn get_bios_info() -> Option<BiosInfo> {
179    bios_cell().clone()
180}
181
182// ── Hardened result cache ─────────────────────────────────────────────────────
183
184static HARDENED: OnceLock<Mutex<Option<bool>>> = OnceLock::new();
185
186fn hardened_cell() -> std::sync::MutexGuard<'static, Option<bool>> {
187    HARDENED.get_or_init(|| Mutex::new(None)).lock().unwrap()
188}
189
190pub fn set_hardened(v: bool) {
191    *hardened_cell() = Some(v);
192}
193
194pub fn get_hardened() -> Option<bool> {
195    *hardened_cell()
196}
197
198// ── Reset all caches ──────────────────────────────────────────────────────────
199
200/// Clear all memo caches (used internally by core::reset()).
201pub fn reset_all() {
202    tech_cache().clear();
203    *single_brand_cell() = None;
204    *multi_brand_cell() = None;
205    *brand_list_cell() = Vec::new();
206    *conclusion_cell() = None;
207    *cpu_brand_cell() = None;
208    *thread_count_cell() = None;
209    *hyperx_cell() = None;
210    *bios_cell() = None;
211    *hardened_cell() = None;
212}