master
rs 67 lines 1.95 KB
Raw
1 // Copyright (C) 2024 Intel Corporation.
2 // Author(s): Zhao Liu <zhao1.liu@intel.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4
5 use std::ptr::addr_of_mut;
6
7 use common::Zeroable;
8 use util::{self, prelude::*};
9
10 /// Each `HPETState` represents a Event Timer Block. The v1 spec supports
11 /// up to 8 blocks. QEMU only uses 1 block (in PC machine).
12 const HPET_MAX_NUM_EVENT_TIMER_BLOCK: usize = 8;
13
14 #[repr(C, packed)]
15 #[derive(Copy, Clone, Default)]
16 pub struct HPETFwEntry {
17 pub event_timer_block_id: u32,
18 pub address: u64,
19 pub min_tick: u16,
20 pub page_prot: u8,
21 }
22 unsafe impl Zeroable for HPETFwEntry {}
23
24 #[repr(C, packed)]
25 #[derive(Copy, Clone, Default)]
26 pub struct HPETFwConfig {
27 pub count: u8,
28 pub hpet: [HPETFwEntry; HPET_MAX_NUM_EVENT_TIMER_BLOCK],
29 }
30 unsafe impl Zeroable for HPETFwConfig {}
31
32 #[allow(non_upper_case_globals)]
33 #[no_mangle]
34 pub static mut hpet_fw_cfg: HPETFwConfig = HPETFwConfig {
35 count: u8::MAX,
36 ..Zeroable::ZERO
37 };
38
39 impl HPETFwConfig {
40 pub(crate) fn assign_hpet_id() -> util::Result<usize> {
41 assert!(bql::is_locked());
42 // SAFETY: all accesses go through these methods, which guarantee
43 // that the accesses are protected by the BQL.
44 let fw_cfg = unsafe { &mut *addr_of_mut!(hpet_fw_cfg) };
45
46 if fw_cfg.count == u8::MAX {
47 // first instance
48 fw_cfg.count = 0;
49 }
50
51 ensure!(fw_cfg.count != 8, "Only 8 instances of HPET are allowed");
52
53 let id: usize = fw_cfg.count.into();
54 fw_cfg.count += 1;
55 Ok(id)
56 }
57
58 pub(crate) fn update_hpet_cfg(hpet_id: usize, timer_block_id: u32, address: u64) {
59 assert!(bql::is_locked());
60 // SAFETY: all accesses go through these methods, which guarantee
61 // that the accesses are protected by the BQL.
62 let fw_cfg = unsafe { &mut *addr_of_mut!(hpet_fw_cfg) };
63
64 fw_cfg.hpet[hpet_id].event_timer_block_id = timer_block_id;
65 fw_cfg.hpet[hpet_id].address = address;
66 }
67 }