1/** 2 * \file 3 */ 4 5/* 6 * Copyright (c) 2009, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14#ifndef LPC_H 15#define LPC_H 16 17#include <stdint.h> 18#include <stdbool.h> 19#include <timer/timer.h> 20#include "apic.h" 21 22 23/** 24 * \brief Check whether an IRQ may be asserted on the VM right now. 25 * 26 * #irq and #irq_prio are defined if the fuction returns true. The describe 27 * the current waiting interrupt and its priority. 28 */ 29typedef bool (*lpc_virtual_irq_pending) (void *user_data, uint8_t *irq, 30 uint8_t *irq_prio); 31 32/** 33 * \brief Assert an IRQ in the virtual machine. 34 */ 35typedef void (*lpc_virtual_irq_handler) (void *user_data, uint8_t irq, 36 uint8_t irq_prio); 37 38#ifndef CONFIG_SVM 39/** 40 * \brief Check whether the guest-VM is accepting interrupts. 41 */ 42typedef bool (*lpc_virtual_irq_accepting) (void *user_data); 43#endif 44 45// LPC Timer 46union lpc_pit_tcw { 47 struct { 48 uint8_t countdown_select : 1; 49 uint8_t mode_select : 3; 50 uint8_t rw_select : 2; 51 uint8_t counter_select : 2; 52 } __attribute__((packed)) u; 53 uint8_t raw; 54} __attribute__((packed)); 55 56union lpc_pit_sbyte { 57 struct { 58 uint8_t countdown_type : 1; 59 uint8_t mode_type : 3; 60 uint8_t rw_mode : 2; 61 uint8_t count_avail : 1; 62 uint8_t out_pin_state : 1; 63 } __attribute__((packed)) u; 64 uint8_t raw; 65} __attribute__((packed)); 66 67 68// NMI 69 70union lpc_nmi_sc { 71 struct { 72 uint8_t tim_cnt2_en : 1; ///< Timer Counter 2 Enable 73 uint8_t spkr_dat_en : 1; ///< Speaker Data Enable 74 uint8_t pci_serr_en : 1; ///< PCI SERR# Enable 75 uint8_t iochk_nmi_en : 1; ///< IOCHK# NMI Enable 76 uint8_t ref_toggle : 1; ///< Refresh Cycle Toggle 77 uint8_t tmr2_out_sts : 1; ///< Timer Counter 2 OUT Status 78 uint8_t iochk_nmi_sts : 1; ///< IOCHK# NMI Source Status 79 uint8_t serr_nmi_sts : 1; ///< SERR# NMI Source Status 80 } __attribute__((packed)) u; 81 uint8_t raw; 82} __attribute__((packed)); 83 84 85// PIC 86 87union lpc_pic_icw1 { 88 struct { 89 uint8_t icw4_req : 1; ///< ICW4 Write Required 90 /// Single or Cascade, 0 means Cascade 91 uint8_t sigl_or_casc : 1; 92 uint8_t adi : 1; 93 uint8_t edge_lvl_bank_sel : 1; ///< Edge/Level Bank Select 94 uint8_t icw_sel : 1; ///< ICW/OCW Select 95 uint8_t rsvd : 3; 96 } __attribute__((packed)) u; 97 uint8_t raw; 98} __attribute__((packed)); 99 100union lpc_pic_icw2 { 101 struct { 102 uint8_t intr_req_lvl : 3; ///< Interrupt Request Level 103 uint8_t intr_vec_base_addr : 5; ///< Interrupt Vector Base Address 104 } __attribute__((packed)) u; 105 uint8_t raw; 106} __attribute__((packed)); 107 108union lpc_pic_icw3 { 109 /// Master Controller 110 struct { 111 uint8_t rsvd1 : 2; 112 /// Cascaded Interrupt Controller IRQ Connection 113 uint8_t casc_slave_ctrlr : 1; 114 uint8_t rsvd2 : 5; 115 } __attribute__((packed)) um; 116 /// Slave Controller 117 struct { 118 uint8_t slave_id_code : 3; ///< Slave Identification Code 119 uint8_t rsvd : 5; 120 } __attribute__((packed)) us; 121 uint8_t raw; 122} __attribute__((packed)); 123 124union lpc_pic_icw4 { 125 struct { 126 uint8_t microproc_mode : 1; ///< Microprocessor Mode 127 uint8_t aeoi : 1; ///< Automatic End of Interrupt 128 uint8_t ms_sl_mode : 1; ///< Master/Slave in Buffered Mode 129 uint8_t buf_mode : 1; ///< Buffered Mode 130 uint8_t sfn_mod : 1; ///< Special Fully Nested Mode 131 uint8_t rsvd : 3; 132 } __attribute__((packed)) u; 133 uint8_t raw; 134} __attribute__((packed)); 135 136union lpc_pic_ocw1 { 137 struct { 138 uint8_t irq_mask : 8; ///< Interrupt Request Mask 139 } __attribute__((packed)) u; 140 uint8_t raw; 141} __attribute__((packed)); 142 143union lpc_pic_ocw2 { 144 struct { 145 uint8_t irq_lvl_sel : 3; ///< Interrupt Level Select 146 uint8_t ocw_sel : 2; ///< OCW Select 147 uint8_t rot_eio_codes : 3; ///< Rotate and EOI Codes 148 } __attribute__((packed)) u; 149 uint8_t raw; 150} __attribute__((packed)); 151 152union lpc_pic_ocw3 { 153 struct { 154 uint8_t reg_read_cmd : 2; ///< Register Read Command 155 uint8_t poll_mode : 1; ///< Poll Mode Command 156 uint8_t ocw_sel : 2; ///< OCW Select 157 uint8_t smm_en : 1; ///< Enable Special Mask Mode 158 uint8_t smm : 1; ///< Special Mask Mode 159 uint8_t rsvd : 1; 160 } __attribute__((packed)) u; 161 uint8_t raw; 162} __attribute__((packed)); 163 164 165// RTC 166 167union lpc_rtc_a { 168 struct { 169 uint8_t rate_sel : 3; ///< Rate Select 170 uint8_t div_chain_sel : 3; ///< Division Chain Select 171 uint8_t uip : 1; ///< Update In Progress 172 } __attribute__((packed)) u; 173 uint8_t raw; 174} __attribute__((packed)); 175 176union lpc_rtc_b { 177 struct { 178 uint8_t dse : 1; ///< Daylight Savings Enable 179 uint8_t hour_format : 1; ///< Hour Format 180 uint8_t data_mode : 1; ///< Data Mode 181 uint8_t sqwe : 1; ///< Square Wave Enable 182 uint8_t uie : 1; ///< Update-Ended Interrupt Enable 183 uint8_t aie : 1; ///< Alarm Interrupt Enable 184 uint8_t pie : 1; ///< Periodic Interrupt Enable 185 uint8_t set : 1; ///< Update Cycle Inhibit 186 } __attribute__((packed)) u; 187 uint8_t raw; 188} __attribute__((packed)); 189 190union lpc_rtc_c { 191 struct { 192 uint8_t rsvd : 4; 193 uint8_t uf : 1; ///< Update-Ended Flag 194 uint8_t af : 1; ///< Alarm Flag 195 uint8_t pf : 1; ///< Periodic Interrupt Flag 196 uint8_t irqf : 1; ///< Interrupt Request Flag 197 } __attribute__((packed)) u; 198 uint8_t raw; 199} __attribute__((packed)); 200 201union lpc_rtc_d { 202 struct { 203 uint8_t data_alarm : 6; ///< Data Alarm 204 uint8_t rsvd : 1; 205 uint8_t vrt : 1; ///< Valid RAM and Time Bit 206 } __attribute__((packed)) u; 207 uint8_t raw; 208} __attribute__((packed)); 209 210union lpc_rtc_prim_ram { 211 struct { 212 uint8_t seconds; 213 uint8_t seconds_alarm; 214 uint8_t minutes; 215 uint8_t minutes_alarm; 216 uint8_t hours; 217 uint8_t hours_alarm; 218 uint8_t day_of_week; 219 uint8_t day_of_month; 220 uint8_t month; 221 uint8_t year; 222 union lpc_rtc_a A; 223 union lpc_rtc_b B; 224 union lpc_rtc_c C; 225 union lpc_rtc_d D; 226 uint8_t ram[114]; 227 } __attribute__((packed)) u; 228 uint8_t raw[128]; 229} __attribute__((packed)); 230 231 232// LPC main data structures 233 234enum lpc_pit_next_byte { 235 LPC_PIT_NONE = 0, 236 LPC_PIT_LSB, 237 LPC_PIT_MSB 238}; 239 240enum lpc_pic_current_icw { 241 LPC_PIC_ICW_NONE, 242 LPC_PIC_ICW_2, 243 LPC_PIC_ICW_3, 244 LPC_PIC_ICW_4 245}; 246 247enum lpc_pic_irq_state { 248 LPC_PIC_IRQ_AVAIL = 0, 249 LPC_PIC_IRQ_PENDING, 250 LPC_PIC_IRQ_ISR 251}; 252 253 254struct lpc { 255 struct apic *apic; ///< The APIC to send IRQs to 256 lpc_virtual_irq_handler virq_handler; 257 lpc_virtual_irq_pending virq_pending; 258#ifndef CONFIG_SVM 259 lpc_virtual_irq_accepting virq_accepting; 260#endif 261 void * virq_user_data; 262 // NMI Controller 263 bool nmi_masked; 264 union lpc_nmi_sc nmi_sc_reg; ///< NMI Status and Control Register 265 266 // Timer 267 union lpc_pit_sbyte sbytes[3]; 268 enum lpc_pit_next_byte counter_current_byte[3]; 269 uint16_t initial_count[3]; 270 bool counter_latched[3]; 271 uint16_t buffer_val[3]; 272 struct timer *timer[3]; 273 274 // PIC 275 // inside the array pos 0 represents the master and 1 the slave controller 276 enum lpc_pic_current_icw current_icw[2]; 277 union lpc_pic_icw1 icw1[2]; 278 union lpc_pic_icw2 icw2[2]; 279 union lpc_pic_icw3 icw3[2]; 280 union lpc_pic_icw4 icw4[2]; 281 union lpc_pic_ocw1 ocw1[2]; 282 union lpc_pic_ocw2 ocw2[2]; 283 union lpc_pic_ocw3 ocw3[2]; 284 enum lpc_pic_irq_state irq_state[16]; 285 int current_irq; 286 287 // RTC 288 uint8_t rtc_prim_addr; 289 union lpc_rtc_prim_ram rtc_prim_ram; 290 uint8_t rtc_sec_addr; 291 uint8_t rtc_sec_ram[128]; 292 struct timer *rtc_timer; 293 uint64_t rtc_timer_elapsed; 294}; 295 296int lpc_init(void); 297struct lpc * lpc_new (lpc_virtual_irq_handler virq_handler, 298 lpc_virtual_irq_pending virq_pending, 299#ifndef CONFIG_SVM 300 lpc_virtual_irq_accepting virq_accepting, 301#endif 302 void *user_data, struct apic *apic); 303int lpc_handle_pio_read (struct lpc *l, uint16_t port, enum opsize size, 304 uint32_t *val); 305int lpc_handle_pio_write (struct lpc *l, uint16_t port, enum opsize size, 306 uint32_t val); 307void lpc_pic_assert_irq (struct lpc *l, uint8_t irq); 308void lpc_pic_process_irqs (struct lpc *l); 309 310void lpc_rtc_get_time_bcd (struct lpc *l, uint8_t *hour, uint8_t *min, 311 uint8_t *sec); 312 313#endif // LPC_H 314