VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/8259InterruptControllerDxe/8259.c@ 53251

Last change on this file since 53251 was 48674, checked in by vboxsync, 11 years ago

EFI: Export newly imported tinaocore UEFI sources to OSE.

  • Property svn:eol-style set to native
File size: 16.4 KB
Line 
1/** @file
2 This contains the installation function for the driver.
3
4Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "8259.h"
16
17//
18// Global for the Legacy 8259 Protocol that is produced by this driver
19//
20EFI_LEGACY_8259_PROTOCOL mInterrupt8259 = {
21 Interrupt8259SetVectorBase,
22 Interrupt8259GetMask,
23 Interrupt8259SetMask,
24 Interrupt8259SetMode,
25 Interrupt8259GetVector,
26 Interrupt8259EnableIrq,
27 Interrupt8259DisableIrq,
28 Interrupt8259GetInterruptLine,
29 Interrupt8259EndOfInterrupt
30};
31
32//
33// Global for the handle that the Legacy 8259 Protocol is installed
34//
35EFI_HANDLE m8259Handle = NULL;
36
37UINT8 mMasterBase = 0xff;
38UINT8 mSlaveBase = 0xff;
39EFI_8259_MODE mMode = Efi8259ProtectedMode;
40UINT16 mProtectedModeMask = 0xffff;
41UINT16 mLegacyModeMask;
42UINT16 mProtectedModeEdgeLevel = 0x0000;
43UINT16 mLegacyModeEdgeLevel;
44
45//
46// Worker Functions
47//
48
49/**
50 Write to mask and edge/level triggered registers of master and slave PICs.
51
52 @param[in] Mask low byte for master PIC mask register,
53 high byte for slave PIC mask register.
54 @param[in] EdgeLevel low byte for master PIC edge/level triggered register,
55 high byte for slave PIC edge/level triggered register.
56
57**/
58VOID
59Interrupt8259WriteMask (
60 IN UINT16 Mask,
61 IN UINT16 EdgeLevel
62 )
63{
64 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, (UINT8) Mask);
65 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, (UINT8) (Mask >> 8));
66 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER, (UINT8) EdgeLevel);
67 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE, (UINT8) (EdgeLevel >> 8));
68}
69
70/**
71 Read from mask and edge/level triggered registers of master and slave PICs.
72
73 @param[out] Mask low byte for master PIC mask register,
74 high byte for slave PIC mask register.
75 @param[out] EdgeLevel low byte for master PIC edge/level triggered register,
76 high byte for slave PIC edge/level triggered register.
77
78**/
79VOID
80Interrupt8259ReadMask (
81 OUT UINT16 *Mask,
82 OUT UINT16 *EdgeLevel
83 )
84{
85 UINT16 MasterValue;
86 UINT16 SlaveValue;
87
88 if (Mask != NULL) {
89 MasterValue = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
90 SlaveValue = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
91
92 *Mask = (UINT16) (MasterValue | (SlaveValue << 8));
93 }
94
95 if (EdgeLevel != NULL) {
96 MasterValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER);
97 SlaveValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE);
98
99 *EdgeLevel = (UINT16) (MasterValue | (SlaveValue << 8));
100 }
101}
102
103//
104// Legacy 8259 Protocol Interface Functions
105//
106
107/**
108 Sets the base address for the 8259 master and slave PICs.
109
110 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
111 @param[in] MasterBase Interrupt vectors for IRQ0-IRQ7.
112 @param[in] SlaveBase Interrupt vectors for IRQ8-IRQ15.
113
114 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
115 @retval EFI_DEVICE_ERROR There was an error while writing to the 8259 PIC.
116
117**/
118EFI_STATUS
119EFIAPI
120Interrupt8259SetVectorBase (
121 IN EFI_LEGACY_8259_PROTOCOL *This,
122 IN UINT8 MasterBase,
123 IN UINT8 SlaveBase
124 )
125{
126 UINT8 Mask;
127
128 //
129 // Set vector base for slave PIC
130 //
131 if (SlaveBase != mSlaveBase) {
132 mSlaveBase = SlaveBase;
133
134 //
135 // Initialization sequence is needed for setting vector base.
136 //
137
138 //
139 // Preserve interrtup mask register before initialization sequence
140 // because it will be cleared during intialization
141 //
142 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
143
144 //
145 // ICW1: cascade mode, ICW4 write required
146 //
147 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x11);
148
149 //
150 // ICW2: new vector base (must be multiple of 8)
151 //
152 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, mSlaveBase);
153
154 //
155 // ICW3: slave indentification code must be 2
156 //
157 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x02);
158
159 //
160 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
161 //
162 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x01);
163
164 //
165 // Restore interrupt mask register
166 //
167 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, Mask);
168 }
169
170 //
171 // Set vector base for master PIC
172 //
173 if (MasterBase != mMasterBase) {
174 mMasterBase = MasterBase;
175
176 //
177 // Initialization sequence is needed for setting vector base.
178 //
179
180 //
181 // Preserve interrtup mask register before initialization sequence
182 // because it will be cleared during intialization
183 //
184 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
185
186 //
187 // ICW1: cascade mode, ICW4 write required
188 //
189 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x11);
190
191 //
192 // ICW2: new vector base (must be multiple of 8)
193 //
194 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, mMasterBase);
195
196 //
197 // ICW3: slave PIC is cascaded on IRQ2
198 //
199 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x04);
200
201 //
202 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
203 //
204 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x01);
205
206 //
207 // Restore interrupt mask register
208 //
209 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, Mask);
210 }
211
212 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
213 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
214
215 return EFI_SUCCESS;
216}
217
218/**
219 Gets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
220
221 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
222 @param[out] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
223 @param[out] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
224 @param[out] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
225 @param[out] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
226
227 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
228 @retval EFI_DEVICE_ERROR There was an error while reading the 8259 PIC.
229
230**/
231EFI_STATUS
232EFIAPI
233Interrupt8259GetMask (
234 IN EFI_LEGACY_8259_PROTOCOL *This,
235 OUT UINT16 *LegacyMask, OPTIONAL
236 OUT UINT16 *LegacyEdgeLevel, OPTIONAL
237 OUT UINT16 *ProtectedMask, OPTIONAL
238 OUT UINT16 *ProtectedEdgeLevel OPTIONAL
239 )
240{
241 if (LegacyMask != NULL) {
242 *LegacyMask = mLegacyModeMask;
243 }
244
245 if (LegacyEdgeLevel != NULL) {
246 *LegacyEdgeLevel = mLegacyModeEdgeLevel;
247 }
248
249 if (ProtectedMask != NULL) {
250 *ProtectedMask = mProtectedModeMask;
251 }
252
253 if (ProtectedEdgeLevel != NULL) {
254 *ProtectedEdgeLevel = mProtectedModeEdgeLevel;
255 }
256
257 return EFI_SUCCESS;
258}
259
260/**
261 Sets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
262
263 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
264 @param[in] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
265 @param[in] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
266 @param[in] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
267 @param[in] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
268
269 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
270 @retval EFI_DEVICE_ERROR There was an error while writing the 8259 PIC.
271
272**/
273EFI_STATUS
274EFIAPI
275Interrupt8259SetMask (
276 IN EFI_LEGACY_8259_PROTOCOL *This,
277 IN UINT16 *LegacyMask, OPTIONAL
278 IN UINT16 *LegacyEdgeLevel, OPTIONAL
279 IN UINT16 *ProtectedMask, OPTIONAL
280 IN UINT16 *ProtectedEdgeLevel OPTIONAL
281 )
282{
283 if (LegacyMask != NULL) {
284 mLegacyModeMask = *LegacyMask;
285 }
286
287 if (LegacyEdgeLevel != NULL) {
288 mLegacyModeEdgeLevel = *LegacyEdgeLevel;
289 }
290
291 if (ProtectedMask != NULL) {
292 mProtectedModeMask = *ProtectedMask;
293 }
294
295 if (ProtectedEdgeLevel != NULL) {
296 mProtectedModeEdgeLevel = *ProtectedEdgeLevel;
297 }
298
299 return EFI_SUCCESS;
300}
301
302/**
303 Sets the mode of the PICs.
304
305 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
306 @param[in] Mode 16-bit real or 32-bit protected mode.
307 @param[in] Mask The value with which to set the interrupt mask.
308 @param[in] EdgeLevel The value with which to set the edge/level mask.
309
310 @retval EFI_SUCCESS The mode was set successfully.
311 @retval EFI_INVALID_PARAMETER The mode was not set.
312
313**/
314EFI_STATUS
315EFIAPI
316Interrupt8259SetMode (
317 IN EFI_LEGACY_8259_PROTOCOL *This,
318 IN EFI_8259_MODE Mode,
319 IN UINT16 *Mask, OPTIONAL
320 IN UINT16 *EdgeLevel OPTIONAL
321 )
322{
323 if (Mode == mMode) {
324 return EFI_SUCCESS;
325 }
326
327 if (Mode == Efi8259LegacyMode) {
328 //
329 // In Efi8259ProtectedMode, mask and edge/level trigger registers should
330 // be changed through this protocol, so we can track them in the
331 // corresponding module variables.
332 //
333 Interrupt8259ReadMask (&mProtectedModeMask, &mProtectedModeEdgeLevel);
334
335 if (Mask != NULL) {
336 //
337 // Update the Mask for the new mode
338 //
339 mLegacyModeMask = *Mask;
340 }
341
342 if (EdgeLevel != NULL) {
343 //
344 // Update the Edge/Level triggered mask for the new mode
345 //
346 mLegacyModeEdgeLevel = *EdgeLevel;
347 }
348
349 mMode = Mode;
350
351 //
352 // Write new legacy mode mask/trigger level
353 //
354 Interrupt8259WriteMask (mLegacyModeMask, mLegacyModeEdgeLevel);
355
356 return EFI_SUCCESS;
357 }
358
359 if (Mode == Efi8259ProtectedMode) {
360 //
361 // Save the legacy mode mask/trigger level
362 //
363 Interrupt8259ReadMask (&mLegacyModeMask, &mLegacyModeEdgeLevel);
364 //
365 // Always force Timer to be enabled after return from 16-bit code.
366 // This always insures that on next entry, timer is counting.
367 //
368 mLegacyModeMask &= 0xFFFE;
369
370 if (Mask != NULL) {
371 //
372 // Update the Mask for the new mode
373 //
374 mProtectedModeMask = *Mask;
375 }
376
377 if (EdgeLevel != NULL) {
378 //
379 // Update the Edge/Level triggered mask for the new mode
380 //
381 mProtectedModeEdgeLevel = *EdgeLevel;
382 }
383
384 mMode = Mode;
385
386 //
387 // Write new protected mode mask/trigger level
388 //
389 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
390
391 return EFI_SUCCESS;
392 }
393
394 return EFI_INVALID_PARAMETER;
395}
396
397/**
398 Translates the IRQ into a vector.
399
400 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
401 @param[in] Irq IRQ0-IRQ15.
402 @param[out] Vector The vector that is assigned to the IRQ.
403
404 @retval EFI_SUCCESS The Vector that matches Irq was returned.
405 @retval EFI_INVALID_PARAMETER Irq is not valid.
406
407**/
408EFI_STATUS
409EFIAPI
410Interrupt8259GetVector (
411 IN EFI_LEGACY_8259_PROTOCOL *This,
412 IN EFI_8259_IRQ Irq,
413 OUT UINT8 *Vector
414 )
415{
416 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
417 return EFI_INVALID_PARAMETER;
418 }
419
420 if (Irq <= Efi8259Irq7) {
421 *Vector = (UINT8) (mMasterBase + Irq);
422 } else {
423 *Vector = (UINT8) (mSlaveBase + (Irq - Efi8259Irq8));
424 }
425
426 return EFI_SUCCESS;
427}
428
429/**
430 Enables the specified IRQ.
431
432 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
433 @param[in] Irq IRQ0-IRQ15.
434 @param[in] LevelTriggered 0 = Edge triggered; 1 = Level triggered.
435
436 @retval EFI_SUCCESS The Irq was enabled on the 8259 PIC.
437 @retval EFI_INVALID_PARAMETER The Irq is not valid.
438
439**/
440EFI_STATUS
441EFIAPI
442Interrupt8259EnableIrq (
443 IN EFI_LEGACY_8259_PROTOCOL *This,
444 IN EFI_8259_IRQ Irq,
445 IN BOOLEAN LevelTriggered
446 )
447{
448 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
449 return EFI_INVALID_PARAMETER;
450 }
451
452 mProtectedModeMask = (UINT16) (mProtectedModeMask & ~(1 << Irq));
453 if (LevelTriggered) {
454 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel | (1 << Irq));
455 } else {
456 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
457 }
458
459 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
460
461 return EFI_SUCCESS;
462}
463
464/**
465 Disables the specified IRQ.
466
467 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
468 @param[in] Irq IRQ0-IRQ15.
469
470 @retval EFI_SUCCESS The Irq was disabled on the 8259 PIC.
471 @retval EFI_INVALID_PARAMETER The Irq is not valid.
472
473**/
474EFI_STATUS
475EFIAPI
476Interrupt8259DisableIrq (
477 IN EFI_LEGACY_8259_PROTOCOL *This,
478 IN EFI_8259_IRQ Irq
479 )
480{
481 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
482 return EFI_INVALID_PARAMETER;
483 }
484
485 mProtectedModeMask = (UINT16) (mProtectedModeMask | (1 << Irq));
486
487 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
488
489 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
490
491 return EFI_SUCCESS;
492}
493
494/**
495 Reads the PCI configuration space to get the interrupt number that is assigned to the card.
496
497 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
498 @param[in] PciHandle PCI function for which to return the vector.
499 @param[out] Vector IRQ number that corresponds to the interrupt line.
500
501 @retval EFI_SUCCESS The interrupt line value was read successfully.
502
503**/
504EFI_STATUS
505EFIAPI
506Interrupt8259GetInterruptLine (
507 IN EFI_LEGACY_8259_PROTOCOL *This,
508 IN EFI_HANDLE PciHandle,
509 OUT UINT8 *Vector
510 )
511{
512 EFI_PCI_IO_PROTOCOL *PciIo;
513 UINT8 InterruptLine;
514 EFI_STATUS Status;
515
516 Status = gBS->HandleProtocol (
517 PciHandle,
518 &gEfiPciIoProtocolGuid,
519 (VOID **) &PciIo
520 );
521 if (EFI_ERROR (Status)) {
522 return EFI_INVALID_PARAMETER;
523 }
524
525 PciIo->Pci.Read (
526 PciIo,
527 EfiPciIoWidthUint8,
528 PCI_INT_LINE_OFFSET,
529 1,
530 &InterruptLine
531 );
532 //
533 // Interrupt line is same location for standard PCI cards, standard
534 // bridge and CardBus bridge.
535 //
536 *Vector = InterruptLine;
537
538 return EFI_SUCCESS;
539}
540
541/**
542 Issues the End of Interrupt (EOI) commands to PICs.
543
544 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
545 @param[in] Irq The interrupt for which to issue the EOI command.
546
547 @retval EFI_SUCCESS The EOI command was issued.
548 @retval EFI_INVALID_PARAMETER The Irq is not valid.
549
550**/
551EFI_STATUS
552EFIAPI
553Interrupt8259EndOfInterrupt (
554 IN EFI_LEGACY_8259_PROTOCOL *This,
555 IN EFI_8259_IRQ Irq
556 )
557{
558 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
559 return EFI_INVALID_PARAMETER;
560 }
561
562 if (Irq >= Efi8259Irq8) {
563 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
564 }
565
566 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
567
568 return EFI_SUCCESS;
569}
570
571/**
572 Driver Entry point.
573
574 @param[in] ImageHandle ImageHandle of the loaded driver.
575 @param[in] SystemTable Pointer to the EFI System Table.
576
577 @retval EFI_SUCCESS One or more of the drivers returned a success code.
578 @retval !EFI_SUCCESS Error installing Legacy 8259 Protocol.
579
580**/
581EFI_STATUS
582EFIAPI
583Install8259 (
584 IN EFI_HANDLE ImageHandle,
585 IN EFI_SYSTEM_TABLE *SystemTable
586 )
587{
588 EFI_STATUS Status;
589 EFI_8259_IRQ Irq;
590
591 //
592 // Initialze mask values from PCDs
593 //
594 mLegacyModeMask = PcdGet16 (Pcd8259LegacyModeMask);
595 mLegacyModeEdgeLevel = PcdGet16 (Pcd8259LegacyModeEdgeLevel);
596
597 //
598 // Clear all pending interrupt
599 //
600 for (Irq = Efi8259Irq0; Irq <= Efi8259Irq15; Irq++) {
601 Interrupt8259EndOfInterrupt (&mInterrupt8259, Irq);
602 }
603
604 //
605 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
606 //
607 Status = Interrupt8259SetVectorBase (&mInterrupt8259, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);
608
609 //
610 // Set all 8259 interrupts to edge triggered and disabled
611 //
612 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
613
614 //
615 // Install 8259 Protocol onto a new handle
616 //
617 Status = gBS->InstallProtocolInterface (
618 &m8259Handle,
619 &gEfiLegacy8259ProtocolGuid,
620 EFI_NATIVE_INTERFACE,
621 &mInterrupt8259
622 );
623 return Status;
624}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette