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