summary refs log tree commit diff stats
path: root/rust/hw/timer/hpet/src/fw_cfg.rs
blob: 619d662ee1e7550c7ad625c809086b8ad104718a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Copyright (C) 2024 Intel Corporation.
// Author(s): Zhao Liu <zhao1.liu@intel.com>
// SPDX-License-Identifier: GPL-2.0-or-later

use std::ptr::addr_of_mut;

use qemu_api::{cell::bql_locked, zeroable::Zeroable};

/// Each `HPETState` represents a Event Timer Block. The v1 spec supports
/// up to 8 blocks. QEMU only uses 1 block (in PC machine).
const HPET_MAX_NUM_EVENT_TIMER_BLOCK: usize = 8;

#[repr(C, packed)]
#[derive(Copy, Clone, Default)]
pub struct HPETFwEntry {
    pub event_timer_block_id: u32,
    pub address: u64,
    pub min_tick: u16,
    pub page_prot: u8,
}
unsafe impl Zeroable for HPETFwEntry {}

#[repr(C, packed)]
#[derive(Copy, Clone, Default)]
pub struct HPETFwConfig {
    pub count: u8,
    pub hpet: [HPETFwEntry; HPET_MAX_NUM_EVENT_TIMER_BLOCK],
}
unsafe impl Zeroable for HPETFwConfig {}

#[allow(non_upper_case_globals)]
#[no_mangle]
pub static mut hpet_fw_cfg: HPETFwConfig = HPETFwConfig {
    count: u8::MAX,
    ..Zeroable::ZERO
};

impl HPETFwConfig {
    pub(crate) fn assign_hpet_id() -> Result<usize, &'static str> {
        assert!(bql_locked());
        // SAFETY: all accesses go through these methods, which guarantee
        // that the accesses are protected by the BQL.
        let mut fw_cfg = unsafe { *addr_of_mut!(hpet_fw_cfg) };

        if fw_cfg.count == u8::MAX {
            // first instance
            fw_cfg.count = 0;
        }

        if fw_cfg.count == 8 {
            Err("Only 8 instances of HPET are allowed")?;
        }

        let id: usize = fw_cfg.count.into();
        fw_cfg.count += 1;
        Ok(id)
    }

    pub(crate) fn update_hpet_cfg(hpet_id: usize, timer_block_id: u32, address: u64) {
        assert!(bql_locked());
        // SAFETY: all accesses go through these methods, which guarantee
        // that the accesses are protected by the BQL.
        let mut fw_cfg = unsafe { *addr_of_mut!(hpet_fw_cfg) };

        fw_cfg.hpet[hpet_id].event_timer_block_id = timer_block_id;
        fw_cfg.hpet[hpet_id].address = address;
    }
}