@@ -48,8 +48,6 @@ const RTC_ISA_IRQ: usize = 8;
48
48
const HPET_CLK_PERIOD : u64 = 10 ; // 10 ns
49
49
const FS_PER_NS : u64 = 1000000 ; // 1000000 femtoseconds == 1 ns
50
50
51
- /// General Capabilities and ID Register
52
- const HPET_CAP_REG : u64 = 0x000 ;
53
51
/// Revision ID (bits 0:7). Revision 1 is implemented (refer to v1.0a spec).
54
52
const HPET_CAP_REV_ID_VALUE : u64 = 0x1 ;
55
53
const HPET_CAP_REV_ID_SHIFT : usize = 0 ;
@@ -65,23 +63,13 @@ const HPET_CAP_VENDER_ID_SHIFT: usize = 16;
65
63
/// Main Counter Tick Period (bits 32:63)
66
64
const HPET_CAP_CNT_CLK_PERIOD_SHIFT : usize = 32 ;
67
65
68
- /// General Configuration Register
69
- const HPET_CFG_REG : u64 = 0x010 ;
70
66
/// Overall Enable (bit 0)
71
67
const HPET_CFG_ENABLE_SHIFT : usize = 0 ;
72
68
/// Legacy Replacement Route (bit 1)
73
69
const HPET_CFG_LEG_RT_SHIFT : usize = 1 ;
74
70
/// Other bits are reserved.
75
71
const HPET_CFG_WRITE_MASK : u64 = 0x003 ;
76
72
77
- /// General Interrupt Status Register
78
- const HPET_INT_STATUS_REG : u64 = 0x020 ;
79
-
80
- /// Main Counter Value Register
81
- const HPET_COUNTER_REG : u64 = 0x0f0 ;
82
-
83
- /// Timer N Configuration and Capability Register (masked by 0x18)
84
- const HPET_TN_CFG_REG : u64 = 0x000 ;
85
73
/// bit 0, 7, and bits 16:31 are reserved.
86
74
/// bit 4, 5, 15, and bits 32:64 are read-only.
87
75
const HPET_TN_CFG_WRITE_MASK : u64 = 0x7f4e ;
@@ -109,11 +97,51 @@ const HPET_TN_CFG_FSB_CAP_SHIFT: usize = 15;
109
97
/// Timer N Interrupt Routing Capability (bits 32:63)
110
98
const HPET_TN_CFG_INT_ROUTE_CAP_SHIFT : usize = 32 ;
111
99
112
- /// Timer N Comparator Value Register (masked by 0x18)
113
- const HPET_TN_CMP_REG : u64 = 0x008 ;
100
+ #[ derive( qemu_api_macros:: TryInto ) ]
101
+ #[ repr( u64 ) ]
102
+ #[ allow( non_camel_case_types) ]
103
+ /// Timer registers, masked by 0x18
104
+ enum TimerRegister {
105
+ /// Timer N Configuration and Capability Register
106
+ CFG = 0 ,
107
+ /// Timer N Comparator Value Register
108
+ CMP = 8 ,
109
+ /// Timer N FSB Interrupt Route Register
110
+ ROUTE = 16 ,
111
+ }
112
+
113
+ #[ derive( qemu_api_macros:: TryInto ) ]
114
+ #[ repr( u64 ) ]
115
+ #[ allow( non_camel_case_types) ]
116
+ /// Global registers
117
+ enum GlobalRegister {
118
+ /// General Capabilities and ID Register
119
+ CAP = 0 ,
120
+ /// General Configuration Register
121
+ CFG = 0x10 ,
122
+ /// General Interrupt Status Register
123
+ INT_STATUS = 0x20 ,
124
+ /// Main Counter Value Register
125
+ COUNTER = 0xF0 ,
126
+ }
114
127
115
- /// Timer N FSB Interrupt Route Register (masked by 0x18)
116
- const HPET_TN_FSB_ROUTE_REG : u64 = 0x010 ;
128
+ enum HPETRegister < ' a > {
129
+ /// Global register in the range from `0` to `0xff`
130
+ Global ( GlobalRegister ) ,
131
+
132
+ /// Register in the timer block `0x100`...`0x3ff`
133
+ Timer ( & ' a BqlRefCell < HPETTimer > , TimerRegister ) ,
134
+
135
+ /// Invalid address
136
+ #[ allow( dead_code) ]
137
+ Unknown ( hwaddr ) ,
138
+ }
139
+
140
+ struct HPETAddrDecode < ' a > {
141
+ shift : u32 ,
142
+ len : u32 ,
143
+ reg : HPETRegister < ' a > ,
144
+ }
117
145
118
146
const fn hpet_next_wrap ( cur_tick : u64 ) -> u64 {
119
147
( cur_tick | 0xffffffff ) + 1
@@ -471,33 +499,21 @@ impl HPETTimer {
471
499
self . update_irq ( true ) ;
472
500
}
473
501
474
- const fn read ( & self , addr : hwaddr , _size : u32 ) -> u64 {
475
- let shift: u64 = ( addr & 4 ) * 8 ;
476
-
477
- match addr & !4 {
478
- HPET_TN_CFG_REG => self . config >> shift, // including interrupt capabilities
479
- HPET_TN_CMP_REG => self . cmp >> shift, // comparator register
480
- HPET_TN_FSB_ROUTE_REG => self . fsb >> shift,
481
- _ => {
482
- // TODO: Add trace point - trace_hpet_ram_read_invalid()
483
- // Reserved.
484
- 0
485
- }
502
+ const fn read ( & self , reg : TimerRegister ) -> u64 {
503
+ use TimerRegister :: * ;
504
+ match reg {
505
+ CFG => self . config , // including interrupt capabilities
506
+ CMP => self . cmp , // comparator register
507
+ ROUTE => self . fsb ,
486
508
}
487
509
}
488
510
489
- fn write ( & mut self , addr : hwaddr , value : u64 , size : u32 ) {
490
- let shift = ( ( addr & 4 ) * 8 ) as u32 ;
491
- let len = std:: cmp:: min ( size * 8 , 64 - shift) ;
492
-
493
- match addr & !4 {
494
- HPET_TN_CFG_REG => self . set_tn_cfg_reg ( shift, len, value) ,
495
- HPET_TN_CMP_REG => self . set_tn_cmp_reg ( shift, len, value) ,
496
- HPET_TN_FSB_ROUTE_REG => self . set_tn_fsb_route_reg ( shift, len, value) ,
497
- _ => {
498
- // TODO: Add trace point - trace_hpet_ram_write_invalid()
499
- // Reserved.
500
- }
511
+ fn write ( & mut self , reg : TimerRegister , value : u64 , shift : u32 , len : u32 ) {
512
+ use TimerRegister :: * ;
513
+ match reg {
514
+ CFG => self . set_tn_cfg_reg ( shift, len, value) ,
515
+ CMP => self . set_tn_cmp_reg ( shift, len, value) ,
516
+ ROUTE => self . set_tn_fsb_route_reg ( shift, len, value) ,
501
517
}
502
518
}
503
519
}
@@ -749,76 +765,72 @@ impl HPETState {
749
765
self . rtc_irq_level . set ( 0 ) ;
750
766
}
751
767
752
- fn timer_and_addr ( & self , addr : hwaddr ) -> Option < ( & BqlRefCell < HPETTimer > , hwaddr ) > {
753
- let timer_id: usize = ( ( addr - 0x100 ) / 0x20 ) as usize ;
768
+ fn decode ( & self , mut addr : hwaddr , size : u32 ) -> HPETAddrDecode {
769
+ let shift = ( ( addr & 4 ) * 8 ) as u32 ;
770
+ let len = std:: cmp:: min ( size * 8 , 64 - shift) ;
754
771
755
- // TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
756
- if timer_id > self . num_timers . get ( ) {
757
- // TODO: Add trace point - trace_hpet_timer_id_out_of_range(timer_id)
758
- None
772
+ addr &= !4 ;
773
+ let reg = if ( 0 ..=0xff ) . contains ( & addr) {
774
+ GlobalRegister :: try_from ( addr) . map ( HPETRegister :: Global )
759
775
} else {
760
- // Keep the complete address so that HPETTimer's read and write could
761
- // detect the invalid access.
762
- Some ( ( & self . timers [ timer_id] , addr & 0x1F ) )
763
- }
776
+ let timer_id: usize = ( ( addr - 0x100 ) / 0x20 ) as usize ;
777
+ if timer_id <= self . num_timers . get ( ) {
778
+ // TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
779
+ TimerRegister :: try_from ( addr)
780
+ . map ( |reg| HPETRegister :: Timer ( & self . timers [ timer_id] , reg) )
781
+ } else {
782
+ // TODO: Add trace point - trace_hpet_timer_id_out_of_range(timer_id)
783
+ Err ( addr)
784
+ }
785
+ } ;
786
+
787
+ // reg is now a Result<HPETRegister, hwaddr>
788
+ // convert the Err case into HPETRegister as well
789
+ let reg = reg. unwrap_or_else ( HPETRegister :: Unknown ) ;
790
+ HPETAddrDecode { shift, len, reg }
764
791
}
765
792
766
793
fn read ( & self , addr : hwaddr , size : u32 ) -> u64 {
767
- let shift: u64 = ( addr & 4 ) * 8 ;
768
-
769
- // address range of all TN regs
770
794
// TODO: Add trace point - trace_hpet_ram_read(addr)
771
- if ( 0x100 ..=0x3ff ) . contains ( & addr) {
772
- match self . timer_and_addr ( addr) {
773
- None => 0 , // Reserved,
774
- Some ( ( timer, tn_addr) ) => timer. borrow_mut ( ) . read ( tn_addr, size) ,
775
- }
776
- } else {
777
- match addr & !4 {
778
- HPET_CAP_REG => self . capability . get ( ) >> shift, /* including HPET_PERIOD 0x004 */
779
- // (CNT_CLK_PERIOD field)
780
- HPET_CFG_REG => self . config . get ( ) >> shift,
781
- HPET_COUNTER_REG => {
782
- let cur_tick: u64 = if self . is_hpet_enabled ( ) {
783
- self . get_ticks ( )
784
- } else {
785
- self . counter . get ( )
786
- } ;
787
-
788
- // TODO: Add trace point - trace_hpet_ram_read_reading_counter(addr & 4,
789
- // cur_tick)
790
- cur_tick >> shift
791
- }
792
- HPET_INT_STATUS_REG => self . int_status . get ( ) >> shift,
793
- _ => {
794
- // TODO: Add trace point- trace_hpet_ram_read_invalid()
795
- // Reserved.
796
- 0
795
+ let HPETAddrDecode { shift, reg, .. } = self . decode ( addr, size) ;
796
+
797
+ use GlobalRegister :: * ;
798
+ use HPETRegister :: * ;
799
+ ( match reg {
800
+ Timer ( timer, tn_reg) => timer. borrow_mut ( ) . read ( tn_reg) ,
801
+ Global ( CAP ) => self . capability . get ( ) , /* including HPET_PERIOD 0x004 */
802
+ Global ( CFG ) => self . config . get ( ) ,
803
+ Global ( INT_STATUS ) => self . int_status . get ( ) ,
804
+ Global ( COUNTER ) => {
805
+ // TODO: Add trace point
806
+ // trace_hpet_ram_read_reading_counter(addr & 4, cur_tick)
807
+ if self . is_hpet_enabled ( ) {
808
+ self . get_ticks ( )
809
+ } else {
810
+ self . counter . get ( )
797
811
}
798
812
}
799
- }
813
+ Unknown ( _) => {
814
+ // TODO: Add trace point- trace_hpet_ram_read_invalid()
815
+ 0
816
+ }
817
+ } ) >> shift
800
818
}
801
819
802
820
fn write ( & self , addr : hwaddr , value : u64 , size : u32 ) {
803
- let shift = ( ( addr & 4 ) * 8 ) as u32 ;
804
- let len = std:: cmp:: min ( size * 8 , 64 - shift) ;
821
+ let HPETAddrDecode { shift, len, reg } = self . decode ( addr, size) ;
805
822
806
823
// TODO: Add trace point - trace_hpet_ram_write(addr, value)
807
- if ( 0x100 ..=0x3ff ) . contains ( & addr) {
808
- match self . timer_and_addr ( addr) {
809
- None => ( ) , // Reserved.
810
- Some ( ( timer, tn_addr) ) => timer. borrow_mut ( ) . write ( tn_addr, value, size) ,
811
- }
812
- } else {
813
- match addr & !0x4 {
814
- HPET_CAP_REG => { } // General Capabilities and ID Register: Read Only
815
- HPET_CFG_REG => self . set_cfg_reg ( shift, len, value) ,
816
- HPET_INT_STATUS_REG => self . set_int_status_reg ( shift, len, value) ,
817
- HPET_COUNTER_REG => self . set_counter_reg ( shift, len, value) ,
818
- _ => {
819
- // TODO: Add trace point - trace_hpet_ram_write_invalid()
820
- // Reserved.
821
- }
824
+ use GlobalRegister :: * ;
825
+ use HPETRegister :: * ;
826
+ match reg {
827
+ Timer ( timer, tn_reg) => timer. borrow_mut ( ) . write ( tn_reg, value, shift, len) ,
828
+ Global ( CAP ) => { } // General Capabilities and ID Register: Read Only
829
+ Global ( CFG ) => self . set_cfg_reg ( shift, len, value) ,
830
+ Global ( INT_STATUS ) => self . set_int_status_reg ( shift, len, value) ,
831
+ Global ( COUNTER ) => self . set_counter_reg ( shift, len, value) ,
832
+ Unknown ( _) => {
833
+ // TODO: Add trace point - trace_hpet_ram_write_invalid()
822
834
}
823
835
}
824
836
}
0 commit comments