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/* A lot of the information used to build these models is take from:
15 * http://www.intel.com/Assets/PDF/datasheet/313082.pdf */
16
17#include "vmkitmon.h"
18#include "lpc.h"
19#include <stdlib.h>
20
21
22#define TCW_RW_LSB      1
23#define TCW_RW_MSB      2
24#define TCW_RW_LSB_MSB  3
25
26#define LPC_PIT_MODE_ONE_SHOT       0
27#define LPC_PIT_MODE_RATEN          2
28#define LPC_PIT_MODE_SWAVE          3
29#define LPC_PIT_TIMER0_PERIOD_NS    838
30
31#define PIC_EOI_NSEOI              1
32#define PIC_EOI_SEOI               3
33
34#define PIT_IRQ     0
35#define RTC_IRQ     8
36
37
38static inline uint8_t
39bcd2bin (uint8_t val)
40{
41    return (val & 0x0f) + (val >> 4) * 10;
42}
43
44static inline uint8_t
45bin2bcd(unsigned val)
46{
47    assert(val < 100);
48    return ((val / 10) << 4) + val % 10;
49}
50
51static inline bool
52pic_irq_masked (struct lpc *l, int irq) {
53    assert(irq < 16);
54
55    // if the IRQ is comming from the slave controller check whether it is
56    // masked on the first controller (IRQ2)
57    if (irq > 7 && l->ocw1[0].u.irq_mask & (1 << 2)) {
58        return true;
59    }
60
61    uint8_t rel_irq = irq & 0x7;
62    int ctrlr = irq >> 3;
63    return l->ocw1[ctrlr].u.irq_mask & (1 << rel_irq);
64}
65
66/**
67 * \brief Scan all pending IRQs and send the most important one up to APIC.
68 */
69void
70lpc_pic_process_irqs (struct lpc *l)
71{
72    bool pending = false;
73
74    // check whether the CPU has an interrupt pending
75    if (l->virq_pending(l->virq_user_data, NULL, NULL)) {
76        assert(l->current_irq >= 0 && l->current_irq < 16);
77        pending = true;
78    }
79
80    // find the most priorized IRQ
81    for (int irq = 0; irq < 16; irq++) {
82        // check whether this IRQ is pending
83        if (l->irq_state[irq] == LPC_PIC_IRQ_PENDING) {
84            assert(irq != 2);
85
86            // check whether this irq has a higher (0 beeing high) priority as
87            // a possible pending one
88            if (pending && irq >= l->current_irq) {
89                // we may return here since no further IRQ may have a higher prior
90                return;
91            }
92
93            // check whether we have to remove a pending interrupt
94            if (pending) {
95                // there is an irq pending with lower priority than the current
96                // one, we have to put it back into pending, it will be replaced
97                // by this interrupt
98                assert(l->irq_state[l->current_irq] == LPC_PIC_IRQ_ISR);
99                l->irq_state[l->current_irq] = LPC_PIC_IRQ_PENDING;
100            }
101
102            // process the irq
103            l->irq_state[irq] = LPC_PIC_IRQ_ISR;
104            l->current_irq = irq;
105
106            // assert the virtual interrupt to the CPU
107            // find out the real irq as it is mapped through the PIC init
108            int ctrlr = irq >> 3;
109            assert(ctrlr == 0 || ctrlr == 1);
110            assert(irq <= 7 || ctrlr == 1);
111            uint8_t real_irq = (l->icw2[ctrlr].u.intr_vec_base_addr << 3) |
112                               (irq & 0x7);
113            /*if (irq != 0) {
114                printf("PIC: assert IRQ%u (real %u), pending %u, current_irq %u\n", irq, real_irq, pending, l->current_irq);
115            }*/
116            l->virq_handler(l->virq_user_data, real_irq, irq);
117            return;
118        }
119    }
120}
121
122/**
123 * \brief Assert an IRQ through the PIC.
124 *
125 * This method asserts an IRQ to the CPU. It does not actually generate virtual
126 * interrupts and instead pushed the IRQ forward to the APIC.
127 */
128void
129lpc_pic_assert_irq (struct lpc *l, uint8_t irq)
130{
131    assert(irq < 16 && irq != 2);
132
133    if (!pic_irq_masked(l, irq) && l->irq_state[irq] == LPC_PIC_IRQ_AVAIL) {
134        // assert the irq
135        l->irq_state[irq] = LPC_PIC_IRQ_PENDING;
136    }
137
138    lpc_pic_process_irqs(l);
139}
140
141static void
142pic_eoi (struct lpc *l, int ctrlr)
143{
144    assert(ctrlr == 0 || ctrlr == 1);
145
146    switch (l->ocw2[ctrlr].u.rot_eio_codes) {
147    case PIC_EOI_NSEOI: {
148        // start at IRQ0 for the master and IRQ8 for the slave controller
149        int irq = ctrlr << 3;
150        for (int i = 0; i < 8; i++, irq++) {
151            if (l->irq_state[irq] == LPC_PIC_IRQ_ISR) {
152                l->irq_state[irq] = LPC_PIC_IRQ_AVAIL;
153                break;
154            }
155        }
156        break;
157    }
158    case PIC_EOI_SEOI: {
159        // irq_lvl_sel holds an number between 0 and 7 which represent the
160        // corresponding IRQ on the master and slave controller
161        int irq = l->ocw2[ctrlr].u.irq_lvl_sel | (ctrlr << 3);
162        l->irq_state[irq] = LPC_PIC_IRQ_AVAIL;
163        break;
164    }
165    default:
166        // we do no support all EOI methods yet
167        assert(!"not reached");
168        break;
169    }
170
171    // after an EOI we should process the remaining IRQs
172    lpc_pic_process_irqs(l);
173}
174
175static inline uint64_t
176truncate_to_opsize (enum opsize size, uint64_t val)
177{
178    switch (size) {
179        case OPSIZE_8:
180            return val & 0xff;
181        case OPSIZE_16:
182            return val & 0xffff;
183        case OPSIZE_32:
184            return val & 0xffffffff;
185        case OPSIZE_64:
186            return val;
187    }
188
189    assert(!"not reached");
190    return 0;
191}
192
193static inline void
194cycle_counter_access_byte (struct lpc *l, int reg)
195{
196    // check whether we have to cycle the byte pointer
197    if (l->sbytes[reg].u.rw_mode == TCW_RW_LSB_MSB) {
198        switch (l->counter_current_byte[reg]) {
199        case LPC_PIT_LSB:
200            l->counter_current_byte[reg] = LPC_PIT_MSB;
201            break;
202        case LPC_PIT_MSB:
203            l->counter_current_byte[reg] = LPC_PIT_LSB;
204            break;
205        case LPC_PIT_NONE:
206            assert(!"not reached");
207        }
208    }
209}
210
211#if 0
212static inline uint32_t
213timer_countdown_reg_read (struct lpc *l, int reg)
214{
215    uint32_t ret;
216
217    assert(l->counters_next_byte[reg] != LPC_PIT_NONE);
218
219    // write the requested byte
220    if (l->counters_next_byte[reg] != LPC_PIT_LSB) {
221        ret = l->counters[reg] & 0xff;
222    } else if (l->counters_next_byte[reg] != LPC_PIT_MSB) {
223        ret = (l->counters[reg] >> 8) & 0xff;
224    }
225
226    cycle_counter_access_byte(l, reg);
227
228    return ret;
229}
230#endif
231
232static inline void
233pit_write_current_byte (struct lpc *l, int reg, uint16_t src, uint8_t *dest)
234{
235    // write the requested byte
236    if (l->counter_current_byte[reg] == LPC_PIT_LSB) {
237        *dest = src;
238    } else if (l->counter_current_byte[reg] == LPC_PIT_MSB) {
239        *dest = src >> 8;
240    } else {
241        assert(!"not reached");
242    }
243}
244
245static inline uint8_t
246pit_counter_read (struct lpc *l, int reg)
247{
248    assert(reg == 0 || reg == 2);
249    assert(l->counter_current_byte[reg] != LPC_PIT_NONE);
250
251    uint16_t val;
252
253    // read the current value
254    if (reg == 2 && !l->nmi_sc_reg.u.tim_cnt2_en) {
255        // if we are dealing with counter 2 and it is disabled we just return
256        // the initial value
257        val = l->initial_count[2];
258    } else {
259        // otherwise we read the value from the real counter
260
261        // if the counter is latched then its value has been stored in the buffer
262        // otherwhise we take it directly from the counter
263        if (l->counter_latched[reg]) {
264            // the value was read before
265            val = l->buffer_val[reg];
266        } else {
267            val = (timer_remaining(l->timer[reg]) * 1000 /
268                  LPC_PIT_TIMER0_PERIOD_NS) % l->initial_count[reg];
269        }
270    }
271
272    uint8_t ret_val;
273    if (l->counter_current_byte[reg] == LPC_PIT_LSB) {
274        ret_val = val;
275    } else {
276        ret_val = val >> 8;
277        // reset a possible latch command
278        l->counter_latched[reg] = false;
279    }
280    cycle_counter_access_byte(l, reg);
281
282    return ret_val;
283}
284
285/**
286 * \brief Handles writes to the ICW or OCW registers of both PICs.
287 *
288 * \param ctrlr     0 inidicates the master and 1 the slave controller
289 * \param port      the relative port (0 or 1) based at 0x20 or 0xa0 accessed
290 */
291static inline uint8_t
292pic_icw_ocw_read (struct lpc *l, int ctrlr, uint16_t port)
293{
294    assert(ctrlr == 0 || ctrlr == 1);
295    assert(port == 0 || port == 1);
296
297    switch (port) {
298    case 0:
299        // ICW1, OCW2, OCW3 are write only
300        assert(!"not reached");
301        break;
302    case 1:
303        return l->ocw1[ctrlr].raw;
304    }
305
306    assert(!"not reached");
307    return 0;
308}
309
310int
311lpc_handle_pio_read (struct lpc *l, uint16_t port, enum opsize size,
312                     uint32_t *val)
313{
314    switch (port) {
315    // PIC
316    case 0x20:
317    case 0x21:
318        *val = pic_icw_ocw_read(l, 0, port - 0x20);
319        return HANDLER_ERR_OK;
320    case 0xa0:
321    case 0xa1:
322        *val = pic_icw_ocw_read(l, 1, port - 0xa0);
323        return HANDLER_ERR_OK;
324
325    // RTC
326    case 0x70:
327    case 0x72:
328    case 0x74:
329    case 0x76:
330        assert(!"these io-ports should not be read");
331        break;
332    // primary ram bank access
333    case 0x71:
334    case 0x75:
335        if (l->rtc_prim_addr < 128) {
336            *val = l->rtc_prim_ram.raw[l->rtc_prim_addr];
337            // clear register C on read
338            if (l->rtc_prim_addr == 0xc) {
339                l->rtc_prim_ram.u.C.raw = 0;
340            }
341        }
342        return HANDLER_ERR_OK;
343    // second ram bank access
344    case 0x73:
345    case 0x77:
346        if (l->rtc_sec_addr < 128) {
347            *val = l->rtc_sec_ram[l->rtc_sec_addr];
348        }
349        return HANDLER_ERR_OK;;
350
351    // NMI
352    case 0x61:
353        // pass the out pin state of PIT counter 2
354        if (l->nmi_sc_reg.u.tim_cnt2_en) {
355            l->nmi_sc_reg.u.tmr2_out_sts = l->sbytes[2].u.out_pin_state;
356        } else {
357            l->nmi_sc_reg.u.tmr2_out_sts = 0;
358        }
359
360        *val = l->nmi_sc_reg.raw;
361        return HANDLER_ERR_OK;
362
363    // Timer
364    case 0x41:
365        assert(!"not reached");
366        break;
367    case 0x40:
368    case 0x42:
369        *val = pit_counter_read(l, port - 0x40);
370        return HANDLER_ERR_OK;
371    case 0x43:
372        *val = 0;
373        return HANDLER_ERR_OK;
374
375    default:
376        printf("lpc: Unhandled read access to port %x\n", port);
377        return HANDLER_ERR_UNHANDELED;
378    }
379
380    return -1;
381}
382
383#if 0
384static void
385rtc_timer_callback (struct timer *t, void *data)
386{
387    struct lpc *l = data;
388
389    // some restrictions
390    // all uniplemented features
391    assert(l->rtc_prim_ram.u.B.u.data_mode == 0);
392    assert(l->rtc_prim_ram.u.B.u.hour_format == 1);
393    assert(l->rtc_prim_ram.u.B.u.aie == 0);
394    assert(l->rtc_prim_ram.u.B.u.pie == 0);
395    assert(l->rtc_prim_ram.u.B.u.set == 0);
396    assert(l->rtc_prim_ram.u.B.u.sqwe == 0);
397
398    uint8_t sec = bcd2bin(l->rtc_prim_ram.u.seconds);
399    uint8_t min = bcd2bin(l->rtc_prim_ram.u.minutes);
400    uint8_t hour = bcd2bin(l->rtc_prim_ram.u.hours);
401    uint8_t dow = bcd2bin(l->rtc_prim_ram.u.day_of_week);
402    uint8_t dom = bcd2bin(l->rtc_prim_ram.u.day_of_month);
403    uint8_t mon = bcd2bin(l->rtc_prim_ram.u.month);
404    uint8_t year = bcd2bin(l->rtc_prim_ram.u.year);
405
406    // increment RTC by one second
407    sec++;
408    if (sec >= 60) {
409        sec = 0;
410        min++;
411    }
412    if (min >= 60) {
413        min = 0;
414        hour++;
415    }
416    if (hour >= 24) {
417        hour = 0;
418        dow++;
419        dom++;
420    }
421    if (dow > 7) {
422        dow = 0;
423    }
424    // FIXME: simply wrong!
425    if (dom > 30) {
426        dom = 0;
427        mon++;
428    }
429    if (mon >= 12) {
430        mon = 0;
431        year++;
432    }
433
434    l->rtc_prim_ram.u.seconds = bin2bcd(sec);
435    l->rtc_prim_ram.u.minutes = bin2bcd(min);
436    l->rtc_prim_ram.u.hours = bin2bcd(hour);
437    l->rtc_prim_ram.u.day_of_week = bin2bcd(dow);
438    l->rtc_prim_ram.u.day_of_month = bin2bcd(dom);
439    l->rtc_prim_ram.u.month = bin2bcd(mon);
440    l->rtc_prim_ram.u.year = bin2bcd(year);
441
442    // trigger update interrupt if desired
443    if (l->rtc_prim_ram.u.B.u.uie) {
444        l->rtc_prim_ram.u.C.u.uf = 1;
445        lpc_pic_assert_irq(l, RTC_IRQ);
446    }
447
448}
449#endif
450
451static void
452handle_counter_timer (struct timer *t, void *user_data)
453{
454    struct lpc *l = user_data;
455
456    int reg;
457    if (t == l->timer[0]) {
458        reg = 0;
459        // assert the IRQ
460        lpc_pic_assert_irq(l, PIT_IRQ);
461    } else if (t == l->timer[2]) {
462        reg = 2;
463    } else {
464        assert(!"timer callback for unknown counter!");
465        return;
466    }
467
468    switch (l->sbytes[reg].u.mode_type) {
469    case LPC_PIT_MODE_ONE_SHOT:
470        // set the out pin to high
471        l->sbytes[reg].u.out_pin_state = 1;
472        // destroy the timer
473        timer_destroy(t);
474        l->timer[reg] = NULL;
475        break;
476
477    case LPC_PIT_MODE_SWAVE:
478        // cycle between zero and one every time the counter rolls
479        // over its initial value
480        l->sbytes[reg].u.out_pin_state = !l->sbytes[reg].u.out_pin_state;
481        break;
482
483    case LPC_PIT_MODE_RATEN:
484        // we do not set the out pin to one for one cycle as it would be on
485        // real hardware
486        // the running timer is peridic therefore we do not need to do anything
487        // here
488        break;
489    }
490}
491
492static inline void
493timer_countdown_reg_write (struct lpc *l, int reg, uint8_t val)
494{
495    uint16_t buf = l->initial_count[reg];
496
497    assert(l->counter_current_byte[reg] != LPC_PIT_NONE);
498
499    // write the requested byte
500    if (l->counter_current_byte[reg] == LPC_PIT_LSB) {
501        l->initial_count[reg] = (buf & 0xff00) | val;
502    } else if (l->counter_current_byte[reg] == LPC_PIT_MSB) {
503        l->initial_count[reg] = (val << 8) | (buf & 0xff);
504    }
505
506    // actions to be done at the end of a counter config cycle
507    // in LSB MSB mode this is the case after MSB has been written in all other
508    // modes this true after all writes
509    // TCW_RW_LSB_MSB ==> LPC_PIT_MSB
510    if (l->sbytes[reg].u.rw_mode != TCW_RW_LSB_MSB ||
511        l->counter_current_byte[reg] == LPC_PIT_MSB) {
512        // counter 0 asserts an interrupt so start a timer on this event
513        if (reg == 0 || reg == 2) {
514            // destroy a possible running timer before creating a new one
515            if (l->timer[reg] != NULL) {
516                timer_destroy(l->timer[reg]);
517            }
518
519            // set up the new timer
520            bool periodic = l->sbytes[reg].u.mode_type != LPC_PIT_MODE_ONE_SHOT;
521
522            // start the PIT timer
523            l->timer[reg] = timer_create((uint64_t)l->initial_count[reg] *
524                                         LPC_PIT_TIMER0_PERIOD_NS / 1000,
525                                         periodic, handle_counter_timer, l);
526            // only start timer 2 if it is enabled
527            if (!(reg == 2 && !l->nmi_sc_reg.u.tim_cnt2_en)) {
528                timer_start(l->timer[reg]);
529            }
530        }
531        // other counters do not assert an IRQ so just pass on the config
532        else {
533            //lpc_timer_config(reg, l->sbytes[reg].u.mode_type,
534            //                 l->initial_count[reg]);
535        }
536    }
537
538    cycle_counter_access_byte(l, reg);
539}
540
541/**
542 * \brief Handles writes to the ICW or OCW registers of both PICs.
543 *
544 * \param ctrlr     0 inidicates the master and 1 the slave controller
545 * \param port      the relative port (0 or 1) based at 0x20 or 0xa0 accessed
546 */
547static inline void
548pic_icw_ocw_write (struct lpc *l, int ctrlr, uint16_t port, uint8_t val)
549{
550    assert(ctrlr == 0 || ctrlr == 1);
551    assert(port == 0 || port == 1);
552
553    switch (port) {
554    case 0:
555        // check whether the IWC cycle should start
556        if (val & 0x10) {
557            // ICW cycle
558            l->icw1[ctrlr].raw = val;
559            assert(l->icw1[ctrlr].u.sigl_or_casc == 0);
560            assert(l->icw1[ctrlr].u.icw_sel != 0);
561            // start the cycle
562            l->current_icw[ctrlr] = LPC_PIC_ICW_2;
563        } else {
564            // OCW write
565            // bit 3 indicates which control word shall be written
566            if (val & 0x8) {
567                // OCW 3
568                l->ocw3[ctrlr].raw = val;
569                assert(l->ocw3[ctrlr].u.ocw_sel == 1);
570            } else {
571                // OCW 2
572                l->ocw2[ctrlr].raw = val;
573                assert(l->ocw2[ctrlr].u.ocw_sel == 0);
574                pic_eoi(l, ctrlr);
575            }
576        }
577        break;
578    case 1:
579        // check whether we are in IWC mode
580        if (l->current_icw[ctrlr] != LPC_PIC_ICW_NONE) {
581            switch (l->current_icw[ctrlr]) {
582            case LPC_PIC_ICW_2:
583                l->icw2[ctrlr].raw = val;
584                assert(l->icw2[ctrlr].u.intr_req_lvl == 0);
585                l->current_icw[ctrlr] = LPC_PIC_ICW_3;
586                break;
587            case LPC_PIC_ICW_3:
588                l->icw3[ctrlr].raw = val;
589                if (ctrlr == 0) {
590                    assert(l->icw3[ctrlr].um.casc_slave_ctrlr == 1);
591                }
592                if (l->icw1[ctrlr].u.icw4_req) {
593                    l->current_icw[ctrlr] = LPC_PIC_ICW_4;
594                } else {
595                    l->current_icw[ctrlr] = LPC_PIC_ICW_NONE;
596                }
597                break;
598            case LPC_PIC_ICW_4:
599                l->icw4[ctrlr].raw = val;
600                assert(l->icw4[ctrlr].u.microproc_mode != 0);
601                assert(!l->icw4[ctrlr].u.buf_mode);
602                assert(!l->icw4[ctrlr].u.sfn_mod);
603                // AEOI not supported yet
604                assert(!l->icw4[ctrlr].u.aeoi);
605                l->current_icw[ctrlr] = LPC_PIC_ICW_NONE;
606                break;
607            default:
608                assert(!"not reached");
609                break;
610            }
611        }
612        // OCW1 write
613        else {
614            l->ocw1[ctrlr].raw = val;
615        }
616        break;
617    default:
618        assert(!"not reached");
619    }
620}
621
622int
623lpc_handle_pio_write (struct lpc *l, uint16_t port, enum opsize size,
624                      uint32_t val)
625{
626    switch (port) {
627    // PIC
628    case 0x20:
629    case 0x21:
630        pic_icw_ocw_write(l, 0, port - 0x20, val);
631        return HANDLER_ERR_OK;
632    case 0xa0:
633    case 0xa1:
634        pic_icw_ocw_write(l, 1, port - 0xa0, val);
635        return HANDLER_ERR_OK;
636
637    //  RTC
638    case 0x70:
639    case 0x74:
640        if ((val >> 7) & 1) {
641            l->nmi_masked = true;
642        } else {
643            l->nmi_masked = false;
644        }
645        l->rtc_prim_addr = val & 0x7f;
646        return HANDLER_ERR_OK;
647    case 0x71:
648    case 0x75:
649        if (l->rtc_prim_addr < 128) {
650            l->rtc_prim_ram.raw[l->rtc_prim_addr] = val;
651        }
652        return HANDLER_ERR_OK;
653    case 0x72:
654    case 0x76:
655        l->rtc_sec_addr = val;
656        return HANDLER_ERR_OK;
657    case 0x73:
658    case 0x77:
659        if (l->rtc_sec_addr < 128) {
660            l->rtc_sec_ram[l->rtc_sec_addr] = val;
661        }
662        return HANDLER_ERR_OK;
663
664    // NMI Controller
665    case 0x61:
666        // only the first 4 bits are writable
667        l->nmi_sc_reg.raw |= val & 0xf;
668        // start/stop the counter 2 if required
669        if (l->timer[2]) {
670            if (l->nmi_sc_reg.u.tim_cnt2_en && !timer_is_running(l->timer[2])) {
671                timer_start(l->timer[2]);
672            } else if (!l->nmi_sc_reg.u.tim_cnt2_en
673                       && timer_is_running(l->timer[2])) {
674                timer_stop(l->timer[2]);
675            }
676        }
677        return HANDLER_ERR_OK;
678
679    // Timer
680    // Write to the countdown registers
681    case 0x40:
682        timer_countdown_reg_write(l, 0, val);
683        return HANDLER_ERR_OK;
684    case 0x41:
685        timer_countdown_reg_write(l, 1, val);
686        return HANDLER_ERR_OK;
687    case 0x42:
688        timer_countdown_reg_write(l, 2, val);
689        return HANDLER_ERR_OK;
690    // Write to the timer control register (TCW)
691    case 0x43: {
692        union lpc_pit_tcw tcw = { .raw = val };
693
694        // check for some unimplemented stuff
695        if (tcw.u.countdown_select != 0) {
696            printf("lpc timer: only binary countdown is supported\n");
697            return HANDLER_ERR_FATAL;
698        }
699        // not all modes are implemented
700        assert(tcw.u.mode_select == LPC_PIT_MODE_ONE_SHOT ||
701               tcw.u.mode_select == LPC_PIT_MODE_RATEN);
702        if (tcw.u.counter_select == 3) {
703            printf("lpc timer: read back command not implemented\n");
704            return HANDLER_ERR_FATAL;
705        }
706
707        // we do not support counter 1
708        assert(tcw.u.counter_select != 1);
709
710        // check for latch command
711        if (tcw.u.rw_select == 0) {
712            l->counter_latched[tcw.u.counter_select] = true;
713            l->buffer_val[tcw.u.counter_select] =
714                (timer_remaining(l->timer[tcw.u.counter_select]) *
715                1000 / LPC_PIT_TIMER0_PERIOD_NS) %
716                l->initial_count[tcw.u.counter_select];
717            return HANDLER_ERR_OK;
718        }
719
720        l->sbytes[tcw.u.counter_select].raw = (uint8_t)val;
721        l->sbytes[tcw.u.counter_select].u.count_avail = 0;
722        l->sbytes[tcw.u.counter_select].u.out_pin_state = 0;
723
724        // set the access mode
725        switch (tcw.u.rw_select) {
726        case TCW_RW_LSB_MSB:
727            l->counter_current_byte[tcw.u.counter_select] = LPC_PIT_LSB;
728            break;
729        // we only support LSB MSB mode atm
730        default:
731            assert(!"not reached");
732        }
733
734        return HANDLER_ERR_OK;
735    }
736
737    default:
738        printf("lpc: Unhandled write access to port %x\n", port);
739        return HANDLER_ERR_UNHANDELED;
740    }
741
742    return -1;
743}
744
745struct lpc *
746lpc_new (lpc_virtual_irq_handler virq_handler,
747         lpc_virtual_irq_pending virq_pending,
748#ifndef CONFIG_SVM
749	 lpc_virtual_irq_accepting virq_accepting,
750#endif
751	 void *user_data, struct apic *apic)
752{
753    struct lpc *ret = calloc(1, sizeof(struct lpc));
754
755    ret->virq_handler = virq_handler;
756    ret->virq_pending = virq_pending;
757#ifndef CONFIG_SVM
758    ret->virq_accepting = virq_accepting;
759#endif
760    ret->virq_user_data = user_data;
761    ret->apic = apic;
762
763    ret->current_irq = -1;
764
765#if 0
766    // RTC init
767    ret->rtc_prim_ram.u.B.u.hour_format = 1;
768    // init some time
769    ret->rtc_prim_ram.u.day_of_month = bin2bcd(29);
770    ret->rtc_prim_ram.u.month = bin2bcd(8);
771    ret->rtc_prim_ram.u.year = bin2bcd(9);
772    // start the RTC timer to to be called every second
773    ret->rtc_timer = timer_create(1000000, true, rtc_timer_callback, ret);
774    timer_start(ret->rtc_timer);
775#endif
776
777    return ret;
778}
779
780void
781lpc_rtc_get_time_bcd (struct lpc *l, uint8_t *hour, uint8_t *min, uint8_t *sec)
782{
783    if (hour != NULL) {
784        *hour = l->rtc_prim_ram.u.hours;
785    }
786    if (min != NULL) {
787        *min = l->rtc_prim_ram.u.minutes;
788    }
789    if (sec != NULL) {
790        *sec = l->rtc_prim_ram.u.seconds;
791    }
792}
793