Serenity Operating System
at portability 213 lines 6.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/Assertions.h> 28#include <AK/Types.h> 29#include <Kernel/Arch/i386/CPU.h> 30#include <Kernel/Interrupts/PIC.h> 31#include <LibBareMetal/IO.h> 32 33namespace Kernel { 34 35// The slave 8259 is connected to the master's IRQ2 line. 36// This is really only to enhance clarity. 37#define SLAVE_INDEX 2 38 39#define PIC0_CTL 0x20 40#define PIC0_CMD 0x21 41#define PIC1_CTL 0xA0 42#define PIC1_CMD 0xA1 43 44#define ICW1_ICW4 0x01 /* ICW4 (not) needed */ 45#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ 46#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ 47#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ 48#define ICW1_INIT 0x10 /* Initialization - required! */ 49 50#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ 51#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ 52#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ 53#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ 54#define ICW4_SFNM 0x10 /* Special fully nested (not) */ 55 56bool inline static is_all_masked(u8 reg) 57{ 58 return reg == 0xFF; 59} 60 61void PIC::disable(u8 irq) 62{ 63 InterruptDisabler disabler; 64 if (is_hard_disabled()) 65 return; 66 u8 imr; 67 if (irq >= 8) { 68 imr = IO::in8(PIC1_CMD); 69 imr |= 1 << (irq - 8); 70 IO::out8(PIC1_CMD, imr); 71 } else { 72 imr = IO::in8(PIC0_CMD); 73 imr |= 1 << irq; 74 IO::out8(PIC0_CMD, imr); 75 } 76 77 if (is_all_masked(imr)) 78 m_enabled = false; 79} 80 81PIC::PIC() 82{ 83 initialize(); 84} 85 86bool PIC::is_vector_enabled(u8 irq) const 87{ 88 u8 imr; 89 if (irq >= 8) { 90 imr = IO::in8(PIC1_CMD); 91 imr &= 1 << (irq - 8); 92 } else { 93 imr = IO::in8(PIC0_CMD); 94 imr &= 1 << irq; 95 } 96 return imr != 0; 97} 98 99void PIC::enable(u8 irq) 100{ 101 InterruptDisabler disabler; 102 if (is_hard_disabled()) 103 return; 104 u8 imr; 105 if (irq >= 8) { 106 imr = IO::in8(PIC1_CMD); 107 imr &= ~(1 << (irq - 8)); 108 IO::out8(PIC1_CMD, imr); 109 } else { 110 imr = IO::in8(PIC0_CMD); 111 imr &= ~(1 << irq); 112 IO::out8(PIC0_CMD, imr); 113 } 114 m_enabled = true; 115} 116 117void PIC::eoi(u8 irq) const 118{ 119 InterruptDisabler disabler; 120 if (is_hard_disabled()) 121 return; 122 if (irq >= 8) 123 IO::out8(PIC1_CTL, 0x20); 124 IO::out8(PIC0_CTL, 0x20); 125} 126 127void PIC::complete_eoi() const 128{ 129 IO::out8(PIC1_CTL, 0x20); 130 IO::out8(PIC0_CTL, 0x20); 131} 132 133void PIC::hard_disable() 134{ 135 InterruptDisabler disabler; 136 remap(0x20); 137 IO::out8(PIC0_CMD, 0xff); 138 IO::out8(PIC1_CMD, 0xff); 139 IRQController::hard_disable(); 140} 141 142void PIC::remap(u8 offset) 143{ 144 /* ICW1 (edge triggered mode, cascading controllers, expect ICW4) */ 145 IO::out8(PIC0_CTL, ICW1_INIT | ICW1_ICW4); 146 IO::out8(PIC1_CTL, ICW1_INIT | ICW1_ICW4); 147 148 /* ICW2 (upper 5 bits specify ISR indices, lower 3 idunno) */ 149 IO::out8(PIC0_CMD, offset); 150 IO::out8(PIC1_CMD, offset + 0x08); 151 152 /* ICW3 (configure master/slave relationship) */ 153 IO::out8(PIC0_CMD, 1 << SLAVE_INDEX); 154 IO::out8(PIC1_CMD, SLAVE_INDEX); 155 156 /* ICW4 (set x86 mode) */ 157 IO::out8(PIC0_CMD, 0x01); 158 IO::out8(PIC1_CMD, 0x01); 159 160 // Mask -- start out with all IRQs disabled. 161 IO::out8(PIC0_CMD, 0xff); 162 IO::out8(PIC1_CMD, 0xff); 163 164 // ...except IRQ2, since that's needed for the master to let through slave interrupts. 165 enable(2); 166} 167 168void PIC::initialize() 169{ 170 /* ICW1 (edge triggered mode, cascading controllers, expect ICW4) */ 171 IO::out8(PIC0_CTL, ICW1_INIT | ICW1_ICW4); 172 IO::out8(PIC1_CTL, ICW1_INIT | ICW1_ICW4); 173 174 /* ICW2 (upper 5 bits specify ISR indices, lower 3 idunno) */ 175 IO::out8(PIC0_CMD, IRQ_VECTOR_BASE); 176 IO::out8(PIC1_CMD, IRQ_VECTOR_BASE + 0x08); 177 178 /* ICW3 (configure master/slave relationship) */ 179 IO::out8(PIC0_CMD, 1 << SLAVE_INDEX); 180 IO::out8(PIC1_CMD, SLAVE_INDEX); 181 182 /* ICW4 (set x86 mode) */ 183 IO::out8(PIC0_CMD, 0x01); 184 IO::out8(PIC1_CMD, 0x01); 185 186 // Mask -- start out with all IRQs disabled. 187 IO::out8(PIC0_CMD, 0xff); 188 IO::out8(PIC1_CMD, 0xff); 189 190 // ...except IRQ2, since that's needed for the master to let through slave interrupts. 191 enable(2); 192 193 kprintf("PIC(i8259): cascading mode, vectors 0x%b-0x%b\n", IRQ_VECTOR_BASE, IRQ_VECTOR_BASE + 0xf); 194} 195 196u16 PIC::get_isr() const 197{ 198 IO::out8(PIC0_CTL, 0x0b); 199 IO::out8(PIC1_CTL, 0x0b); 200 u8 isr0 = IO::in8(PIC0_CTL); 201 u8 isr1 = IO::in8(PIC1_CTL); 202 return (isr1 << 8) | isr0; 203} 204 205u16 PIC::get_irr() const 206{ 207 IO::out8(PIC0_CTL, 0x0a); 208 IO::out8(PIC1_CTL, 0x0a); 209 u8 irr0 = IO::in8(PIC0_CTL); 210 u8 irr1 = IO::in8(PIC1_CTL); 211 return (irr1 << 8) | irr0; 212} 213}