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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
/*
* Copyright (c) 2012-2014 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <kern/assert.h>
#include <kern/init.h>
#include <kern/panic.h>
#include <kern/stdint.h>
#include <machine/io.h>
#include <machine/cpu.h>
#include <machine/pic.h>
#include <machine/trap.h>
/*
* I/O ports.
*/
#define PIC_MASTER_CMD 0x20
#define PIC_MASTER_IMR 0x21
#define PIC_SLAVE_CMD 0xa0
#define PIC_SLAVE_IMR 0xa1
/*
* Register bits.
*/
#define PIC_ICW1_IC4 0x01
#define PIC_ICW1_INIT 0x10
#define PIC_ICW4_8086 0x01
#define PIC_OCW3_ISR 0x0b
#define PIC_EOI 0x20
/*
* Special interrupts.
*/
#define PIC_SLAVE_INTR 2
#define PIC_SPURIOUS_INTR 7
#define PIC_NR_INTRS 8
void __init
pic_setup(void)
{
/* ICW 1 - State that ICW 4 will be sent */
io_write_byte(PIC_MASTER_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4);
io_write_byte(PIC_SLAVE_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4);
/* ICW 2 */
io_write_byte(PIC_MASTER_IMR, TRAP_PIC_BASE);
io_write_byte(PIC_SLAVE_IMR, TRAP_PIC_BASE + PIC_NR_INTRS);
/* ICW 3 - Set up cascading */
io_write_byte(PIC_MASTER_IMR, 1 << PIC_SLAVE_INTR);
io_write_byte(PIC_SLAVE_IMR, PIC_SLAVE_INTR);
/* ICW 4 - Set 8086 mode */
io_write_byte(PIC_MASTER_IMR, PIC_ICW4_8086);
io_write_byte(PIC_SLAVE_IMR, PIC_ICW4_8086);
/* OCW 1 - Mask all interrupts */
io_write_byte(PIC_MASTER_IMR, 0xff);
io_write_byte(PIC_SLAVE_IMR, 0xff);
}
static void
pic_eoi(unsigned long intr)
{
if (intr >= PIC_NR_INTRS) {
io_write_byte(PIC_SLAVE_CMD, PIC_EOI);
}
io_write_byte(PIC_MASTER_CMD, PIC_EOI);
}
static uint8_t
pic_read_isr(uint16_t port)
{
io_write_byte(port, PIC_OCW3_ISR);
return io_read_byte(port);
}
void
pic_spurious_intr(struct trap_frame *frame)
{
unsigned long intr;
uint8_t isr;
intr = frame->vector - TRAP_PIC_BASE;
assert((intr == PIC_SPURIOUS_INTR)
|| (intr == (PIC_NR_INTRS + PIC_SPURIOUS_INTR)));
if (intr == PIC_SPURIOUS_INTR) {
isr = pic_read_isr(PIC_MASTER_CMD);
if (isr & (1 << PIC_SPURIOUS_INTR)) {
panic("pic: real interrupt %lu", intr);
}
} else {
isr = pic_read_isr(PIC_SLAVE_CMD);
if (isr & (1 << PIC_SPURIOUS_INTR)) {
panic("pic: real interrupt %lu", intr);
}
pic_eoi(PIC_SLAVE_INTR);
}
}
|