@@ -2,11 +2,16 @@ use alloc::vec::Vec;
2
2
use core:: ptr:: NonNull ;
3
3
4
4
use align_address:: Align ;
5
+ use arm_gic:: { IntId , Trigger } ;
5
6
use hermit_sync:: { InterruptTicketMutex , without_interrupts} ;
6
7
use virtio:: mmio:: { DeviceRegisters , DeviceRegistersVolatileFieldAccess } ;
7
8
use volatile:: VolatileRef ;
8
9
10
+ use crate :: arch:: aarch64:: kernel:: interrupts:: GIC ;
9
11
use crate :: arch:: aarch64:: mm:: paging:: { self , PageSize } ;
12
+ #[ cfg( feature = "console" ) ]
13
+ use crate :: drivers:: console:: VirtioConsoleDriver ;
14
+ #[ cfg( any( feature = "tcp" , feature = "udp" ) ) ]
10
15
use crate :: drivers:: net:: virtio:: VirtioNetDriver ;
11
16
use crate :: drivers:: virtio:: transport:: mmio:: { self as mmio_virtio, VirtioDriver } ;
12
17
use crate :: init_cell:: InitCell ;
@@ -17,13 +22,26 @@ pub(crate) static MMIO_DRIVERS: InitCell<Vec<MmioDriver>> = InitCell::new(Vec::n
17
22
pub ( crate ) enum MmioDriver {
18
23
#[ cfg( any( feature = "tcp" , feature = "udp" ) ) ]
19
24
VirtioNet ( InterruptTicketMutex < VirtioNetDriver > ) ,
25
+ #[ cfg( feature = "console" ) ]
26
+ VirtioConsole ( InterruptTicketMutex < VirtioConsoleDriver > ) ,
20
27
}
21
28
22
29
impl MmioDriver {
23
30
#[ cfg( any( feature = "tcp" , feature = "udp" ) ) ]
24
31
fn get_network_driver ( & self ) -> Option < & InterruptTicketMutex < VirtioNetDriver > > {
25
32
match self {
26
33
Self :: VirtioNet ( drv) => Some ( drv) ,
34
+ #[ cfg( feature = "console" ) ]
35
+ _ => None ,
36
+ }
37
+ }
38
+
39
+ #[ cfg( feature = "console" ) ]
40
+ fn get_console_driver ( & self ) -> Option < & InterruptTicketMutex < VirtioConsoleDriver > > {
41
+ match self {
42
+ Self :: VirtioConsole ( drv) => Some ( drv) ,
43
+ #[ cfg( any( feature = "tcp" , feature = "udp" ) ) ]
44
+ _ => None ,
27
45
}
28
46
}
29
47
}
@@ -40,6 +58,14 @@ pub(crate) fn get_network_driver() -> Option<&'static InterruptTicketMutex<Virti
40
58
. find_map ( |drv| drv. get_network_driver ( ) )
41
59
}
42
60
61
+ #[ cfg( feature = "console" ) ]
62
+ pub ( crate ) fn get_console_driver ( ) -> Option < & ' static InterruptTicketMutex < VirtioConsoleDriver > > {
63
+ MMIO_DRIVERS
64
+ . get ( ) ?
65
+ . iter ( )
66
+ . find_map ( |drv| drv. get_console_driver ( ) )
67
+ }
68
+
43
69
pub fn init_drivers ( ) {
44
70
without_interrupts ( || {
45
71
if let Some ( fdt) = crate :: env:: fdt ( ) {
@@ -53,12 +79,16 @@ pub fn init_drivers() {
53
79
. next ( )
54
80
. unwrap ( ) ;
55
81
let mut irq = 0 ;
82
+ let mut irqtype = 0 ;
83
+ let mut irqflags = 0 ;
56
84
57
85
for prop in node. properties ( ) {
58
86
if prop. name == "interrupts" {
59
- irq = u32:: from_be_bytes ( prop. value [ 4 ..8 ] . try_into ( ) . unwrap ( ) )
60
- . try_into ( )
61
- . unwrap ( ) ;
87
+ irqtype =
88
+ u32:: from_be_bytes ( prop. value [ 0 ..4 ] . try_into ( ) . unwrap ( ) ) ;
89
+ irq = u32:: from_be_bytes ( prop. value [ 4 ..8 ] . try_into ( ) . unwrap ( ) ) ;
90
+ irqflags =
91
+ u32:: from_be_bytes ( prop. value [ 8 ..12 ] . try_into ( ) . unwrap ( ) ) ;
62
92
break ;
63
93
}
64
94
}
@@ -95,17 +125,100 @@ pub fn init_drivers() {
95
125
96
126
// Verify the device-ID to find the network card
97
127
let id = mmio. as_ptr ( ) . device_id ( ) . read ( ) ;
98
-
99
- #[ cfg( any( feature = "tcp" , feature = "udp" ) ) ]
100
- if id == virtio:: Id :: Net {
101
- trace ! ( "Found network card at {mmio:p}, irq: {irq}" ) ;
102
- if let Ok ( VirtioDriver :: Network ( drv) ) =
103
- mmio_virtio:: init_device ( mmio, irq. try_into ( ) . unwrap ( ) )
104
- {
105
- register_driver ( MmioDriver :: VirtioNet (
106
- hermit_sync:: InterruptTicketMutex :: new ( drv) ,
107
- ) ) ;
128
+ let cpu_id: usize = 0 ;
129
+
130
+ match id {
131
+ #[ cfg( any( feature = "tcp" , feature = "udp" ) ) ]
132
+ virtio:: Id :: Net => {
133
+ debug ! (
134
+ "Found network card at {mmio:p}, irq: {irq}, type: {irqtype}, flags: {irqflags}"
135
+ ) ;
136
+ if let Ok ( VirtioDriver :: Network ( drv) ) =
137
+ mmio_virtio:: init_device ( mmio, irq. try_into ( ) . unwrap ( ) )
138
+ && let Some ( gic) = GIC . lock ( ) . as_mut ( )
139
+ {
140
+ // enable timer interrupt
141
+ let virtio_irqid = if irqtype == 1 {
142
+ IntId :: ppi ( irq)
143
+ } else if irqtype == 0 {
144
+ IntId :: spi ( irq)
145
+ } else {
146
+ panic ! ( "Invalid interrupt type" ) ;
147
+ } ;
148
+ gic. set_interrupt_priority (
149
+ virtio_irqid,
150
+ Some ( cpu_id) ,
151
+ 0x00 ,
152
+ ) ;
153
+ if ( irqflags & 0xf ) == 4 || ( irqflags & 0xf ) == 8 {
154
+ gic. set_trigger (
155
+ virtio_irqid,
156
+ Some ( cpu_id) ,
157
+ Trigger :: Level ,
158
+ ) ;
159
+ } else if ( irqflags & 0xf ) == 2 || ( irqflags & 0xf ) == 1 {
160
+ gic. set_trigger (
161
+ virtio_irqid,
162
+ Some ( cpu_id) ,
163
+ Trigger :: Edge ,
164
+ ) ;
165
+ } else {
166
+ panic ! ( "Invalid interrupt level!" ) ;
167
+ }
168
+ gic. enable_interrupt ( virtio_irqid, Some ( cpu_id) , true ) ;
169
+
170
+ register_driver ( MmioDriver :: VirtioNet (
171
+ hermit_sync:: InterruptTicketMutex :: new ( drv) ,
172
+ ) ) ;
173
+ }
174
+ }
175
+ #[ cfg( feature = "console" ) ]
176
+ virtio:: Id :: Console => {
177
+ debug ! (
178
+ "Found console at {mmio:p}, irq: {irq}, type: {irqtype}, flags: {irqflags}"
179
+ ) ;
180
+ if let Ok ( VirtioDriver :: Console ( drv) ) =
181
+ mmio_virtio:: init_device ( mmio, irq. try_into ( ) . unwrap ( ) )
182
+ {
183
+ if let Some ( gic) = GIC . lock ( ) . as_mut ( ) {
184
+ // enable timer interrupt
185
+ let virtio_irqid = if irqtype == 1 {
186
+ IntId :: ppi ( irq)
187
+ } else if irqtype == 0 {
188
+ IntId :: spi ( irq)
189
+ } else {
190
+ panic ! ( "Invalid interrupt type" ) ;
191
+ } ;
192
+ gic. set_interrupt_priority (
193
+ virtio_irqid,
194
+ Some ( cpu_id) ,
195
+ 0x00 ,
196
+ ) ;
197
+ if ( irqflags & 0xf ) == 4 || ( irqflags & 0xf ) == 8 {
198
+ gic. set_trigger (
199
+ virtio_irqid,
200
+ Some ( cpu_id) ,
201
+ Trigger :: Level ,
202
+ ) ;
203
+ } else if ( irqflags & 0xf ) == 2 || ( irqflags & 0xf ) == 1
204
+ {
205
+ gic. set_trigger (
206
+ virtio_irqid,
207
+ Some ( cpu_id) ,
208
+ Trigger :: Edge ,
209
+ ) ;
210
+ } else {
211
+ panic ! ( "Invalid interrupt level!" ) ;
212
+ }
213
+ gic. enable_interrupt ( virtio_irqid, Some ( cpu_id) , true ) ;
214
+
215
+ register_driver ( MmioDriver :: VirtioConsole (
216
+ hermit_sync:: InterruptTicketMutex :: new ( * drv) ,
217
+ ) ) ;
218
+ }
219
+ }
108
220
}
221
+ _ => { }
109
222
}
110
223
}
111
224
}
@@ -117,4 +230,15 @@ pub fn init_drivers() {
117
230
} ) ;
118
231
119
232
MMIO_DRIVERS . finalize ( ) ;
233
+
234
+ #[ cfg( feature = "console" ) ]
235
+ {
236
+ if get_console_driver ( ) . is_some ( ) {
237
+ info ! ( "Switch to virtio console" ) ;
238
+ crate :: console:: CONSOLE
239
+ . lock ( )
240
+ . inner
241
+ . switch_to_virtio_console ( ) ;
242
+ }
243
+ }
120
244
}
0 commit comments