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