ccp_msr/linux_x86_64/
msr_x86_64.rs

1/*
2 * Copyright 2024 Fluence DAO
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use ccp_shared::types::LogicalCoreId;
18
19use super::msr_mode::MSRMode;
20use super::utils;
21use crate::state::MSRCpuPreset;
22use crate::state::MSRPresetItem;
23use crate::MSREnforce;
24use crate::MSRResult;
25
26const DEFAULT_CORE_TO_READ_MSR: LogicalCoreId = LogicalCoreId::new(0);
27
28#[derive(Clone, Debug)]
29pub struct MSRModeEnforcer {
30    is_enabled: bool,
31    original_preset: MSRCpuPreset,
32}
33
34impl MSRModeEnforcer {
35    /// Initialize enforces by reading the original values from OS,
36    /// this method should typically be called only once in CCP.
37    pub fn from_os(is_enabled: bool) -> Self {
38        if !is_enabled {
39            return Self {
40                is_enabled,
41                original_preset: <_>::default(),
42            };
43        }
44
45        let mode = MSRMode::detect();
46        let preset = mode.get_optimal_cpu_preset();
47
48        let original_items = preset
49            .items()
50            .filter_map(|item| {
51                let register_id = item.register_id();
52                let value = utils::read_msr(register_id, DEFAULT_CORE_TO_READ_MSR).ok()?;
53                Some(MSRPresetItem::new(register_id, value))
54            })
55            .collect();
56        let original_preset = MSRCpuPreset::new(original_items);
57
58        Self {
59            is_enabled,
60            original_preset,
61        }
62    }
63
64    pub fn from_preset(is_enabled: bool, original_preset: MSRCpuPreset) -> Self {
65        Self {
66            is_enabled,
67            original_preset,
68        }
69    }
70
71    pub fn original_preset(&self) -> &MSRCpuPreset {
72        &self.original_preset
73    }
74}
75
76impl MSREnforce for MSRModeEnforcer {
77    fn enforce(&mut self, core_id: LogicalCoreId) -> MSRResult<()> {
78        use super::msr_mode::MSR_MODE;
79
80        if !self.is_enabled {
81            return Ok(());
82        }
83
84        let mode = *MSR_MODE;
85        tracing::debug!("Global MSR mode: mode:{:?}.", mode);
86
87        let preset = mode.get_optimal_cpu_preset();
88        for item in preset.items() {
89            // TODO Check for errors here and rollback/clean the stored state
90            write(*item, core_id)?;
91        }
92
93        Ok(())
94    }
95
96    fn cease(&self, core_id: LogicalCoreId) -> MSRResult<()> {
97        if !self.is_enabled {
98            return Ok(());
99        }
100
101        for item in self.original_preset.items() {
102            write(*item, core_id)?;
103        }
104        Ok(())
105    }
106}
107
108pub fn write(item: MSRPresetItem, core_id: LogicalCoreId) -> MSRResult<()> {
109    let value_to_write = if item.mask() != MSRPresetItem::NO_MASK {
110        let old_value = utils::read_msr(item.register_id(), core_id)?;
111        MSRPresetItem::masked_value(old_value, item.value(), item.mask())
112    } else {
113        item.value()
114    };
115
116    tracing::debug!(
117        "Write MSR register_id {} value {:#X} at logical CPU {}  ",
118        item.register_id(),
119        value_to_write,
120        core_id
121    );
122    utils::write_msr(item.register_id(), value_to_write, core_id)
123}