source: bootcd/isolinux/syslinux-6.03/core/fs/pxe/isr.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 6.5 KB
Line 
1/*
2 * core/fs/pxe/isr.c
3 *
4 * Stub invoked on return from real mode including from an interrupt.
5 * Interrupts are locked out on entry.
6 */
7
8#include "core.h"
9#include "thread.h"
10#include "pxe.h"
11#include <string.h>
12#include <sys/cpu.h>
13#include <sys/io.h>
14
15extern uint8_t pxe_irq_pending;
16extern volatile uint8_t pxe_need_poll;
17static DECLARE_INIT_SEMAPHORE(pxe_receive_thread_sem, 0);
18static DECLARE_INIT_SEMAPHORE(pxe_poll_thread_sem, 0);
19static struct thread *pxe_thread, *poll_thread;
20
21#ifndef PXE_POLL_FORCE
22#  define PXE_POLL_FORCE 0
23#endif
24
25#ifndef PXE_POLL_BY_MODEL
26#  define PXE_POLL_BY_MODEL 1
27#endif
28
29/*
30 * Note: this *must* be called with interrupts enabled.
31 */
32static bool install_irq_vector(uint8_t irq, void (*isr)(void), far_ptr_t *old)
33{
34    far_ptr_t *entry;
35    unsigned int vec;
36    uint8_t mask, mymask;
37    uint32_t now;
38    bool ok;
39
40    if (irq < 8)
41        vec = irq + 0x08;
42    else if (irq < 16)
43        vec = (irq - 8) + 0x70;
44    else
45        return false;
46
47    cli();
48
49    if (pxe_need_poll) {
50        sti();
51        return false;
52    }
53
54    entry = (far_ptr_t *)(vec << 2);
55    *old = *entry;
56    entry->ptr = (uint32_t)isr;
57
58    /* Enable this interrupt at the PIC level, just in case... */
59    mymask = ~(1 << (irq & 7));
60    if (irq >= 8) {
61        mask = inb(0x21);
62        mask &= ~(1 << 2);      /* Enable cascade */
63        outb(mask, 0x21);
64        mask = inb(0xa1);
65        mask &= mymask;
66        outb(mask, 0xa1);
67    } else {
68        mask = inb(0x21);
69        mask &= mymask;
70        outb(mask, 0x21);
71    }
72
73    sti();
74
75    now = jiffies();
76
77    /* Some time to watch for stuck interrupts */
78    while (jiffies() - now < 4 && (ok = !pxe_need_poll))
79        hlt();
80
81    if (!ok)
82        *entry = *old;          /* Restore the old vector */
83
84    ddprintf("UNDI: IRQ %d(0x%02x): %04x:%04x -> %04x:%04x\n", irq, vec,
85           old->seg, old->offs, entry->seg, entry->offs);
86
87    return ok;
88}
89
90static bool uninstall_irq_vector(uint8_t irq, void (*isr), far_ptr_t *old)
91{
92    far_ptr_t *entry;
93    unsigned int vec;
94    bool rv;
95
96    if (!irq)
97        return true;            /* Nothing to uninstall */
98
99    if (irq < 8)
100        vec = irq + 0x08;
101    else if (irq < 16)
102        vec = (irq - 8) + 0x70;
103    else
104        return false;
105
106    cli();
107
108    entry = (far_ptr_t *)(vec << 2);
109
110    if (entry->ptr != (uint32_t)isr) {
111        rv = false;
112    } else {
113        *entry = *old;
114        rv = true;
115    }
116
117    sti();
118    return rv;
119}
120
121static void pxe_poll_wakeups(void)
122{
123    static jiffies_t last_jiffies = 0;
124    jiffies_t now = jiffies();
125
126    if (pxe_need_poll == 1) {
127        /* If we need polling now, activate polling */
128        pxe_need_poll = 3;
129        sem_up(&pxe_poll_thread_sem);
130    }
131
132    if (now != last_jiffies) {
133        last_jiffies = now;
134        __thread_process_timeouts();
135    }
136
137    if (pxe_irq_pending) {
138        pxe_irq_pending = 0;
139        sem_up(&pxe_receive_thread_sem);
140    }
141}
142
143static void pxe_process_irq(void)
144{
145    static __lowmem t_PXENV_UNDI_ISR isr;
146
147    uint16_t func = PXENV_UNDI_ISR_IN_PROCESS; /* First time */
148    bool done = false;
149
150    while (!done) {
151        memset(&isr, 0, sizeof isr);
152        isr.FuncFlag = func;
153        func = PXENV_UNDI_ISR_IN_GET_NEXT; /* Next time */
154
155        pxe_call(PXENV_UNDI_ISR, &isr);
156
157        switch (isr.FuncFlag) {
158        case PXENV_UNDI_ISR_OUT_DONE:
159            done = true;
160            break;
161
162        case PXENV_UNDI_ISR_OUT_TRANSMIT:
163            /* Transmit complete - nothing for us to do */
164            break;
165
166        case PXENV_UNDI_ISR_OUT_RECEIVE:
167            undiif_input(&isr);
168            break;
169
170        case PXENV_UNDI_ISR_OUT_BUSY:
171        /* ISR busy, this should not happen */
172            done = true;
173            break;
174
175        default:
176        /* Invalid return code, this should not happen */
177            done = true;
178            break;
179        }
180    }
181}
182
183static void pxe_receive_thread(void *dummy)
184{
185    (void)dummy;
186
187    for (;;) {
188        sem_down(&pxe_receive_thread_sem, 0);
189        pxe_process_irq();
190    }
191}
192
193static bool pxe_isr_poll(void)
194{
195    static __lowmem t_PXENV_UNDI_ISR isr;
196
197    isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
198    pxe_call(PXENV_UNDI_ISR, &isr);
199
200    return isr.FuncFlag == PXENV_UNDI_ISR_OUT_OURS;
201}
202
203static void pxe_poll_thread(void *dummy)
204{
205    (void)dummy;
206
207    /* Block indefinitely unless activated */
208    sem_down(&pxe_poll_thread_sem, 0);
209
210    for (;;) {
211        cli();
212        if (pxe_receive_thread_sem.count < 0 && pxe_isr_poll())
213            sem_up(&pxe_receive_thread_sem);
214        else
215            __schedule();
216        sti();
217        cpu_relax();
218    }
219}
220
221/*
222 * This does preparations and enables the PXE thread
223 */
224void pxe_init_isr(void)
225{
226    start_idle_thread();
227    sched_hook_func = pxe_poll_wakeups;
228    /*
229     * Run the pxe receive thread at elevated priority, since the UNDI
230     * stack is likely to have very limited memory available; therefore to
231     * avoid packet loss we need to move it into memory that we ourselves
232     * manage, as soon as possible.
233     */
234    core_pm_hook = __schedule;
235
236    pxe_thread = start_thread("pxe receive", 16384, -20,
237                              pxe_receive_thread, NULL);
238}
239
240/*
241 * Actually start the interrupt routine inside the UNDI stack
242 */
243void pxe_start_isr(void)
244{
245    int irq = pxe_undi_info.IntNumber;
246
247    if (irq == 2)
248        irq = 9;                /* IRQ 2 is really IRQ 9 */
249    else if (irq > 15)
250        irq = 0;                /* Invalid IRQ */
251
252    pxe_irq_vector = irq;
253
254    if (irq) {
255        if (!install_irq_vector(irq, pxe_isr, &pxe_irq_chain))
256            irq = 0;            /* Install failed or stuck interrupt */
257    }
258   
259    poll_thread = start_thread("pxe poll", 4096, POLL_THREAD_PRIORITY,
260                               pxe_poll_thread, NULL);
261
262    if (!irq || !(pxe_undi_iface.ServiceFlags & PXE_UNDI_IFACE_FLAG_IRQ)) {
263        asm volatile("orb $1,%0" : "+m" (pxe_need_poll));
264        dprintf("pxe_start_isr: forcing pxe_need_poll\n");
265    } else if (PXE_POLL_BY_MODEL) {
266        dprintf("pxe_start_isr: trying poll by model\n");
267        int hwad = ((int)MAC[0] << 16) + ((int)MAC[1] << 8) + MAC[2];
268        dprintf("pxe_start_isr: got %06x %04x\n", hwad, pxe_undi_iface.ServiceFlags);
269        if ((hwad == 0x000023ae) && (pxe_undi_iface.ServiceFlags == 0xdc1b) ||
270            (hwad == 0x005c260a) && (pxe_undi_iface.ServiceFlags == 0xdc1b) ||
271            (hwad == 0x00180373) && (pxe_undi_iface.ServiceFlags == 0xdc1b)) {
272                asm volatile("orb $1,%0" : "+m" (pxe_need_poll));
273                dprintf("pxe_start_isr: forcing pxe_need_poll by model\n");
274        }
275    }
276}
277
278int reset_pxe(void)
279{
280    static __lowmem struct s_PXENV_UNDI_CLOSE undi_close;
281
282    sched_hook_func = NULL;
283    core_pm_hook = core_pm_null_hook;
284    kill_thread(pxe_thread);
285
286    memset(&undi_close, 0, sizeof(undi_close));
287    pxe_call(PXENV_UNDI_CLOSE, &undi_close);
288
289    if (undi_close.Status)
290        printf("PXENV_UNDI_CLOSE failed: 0x%x\n", undi_close.Status);
291
292    if (pxe_irq_vector)
293        uninstall_irq_vector(pxe_irq_vector, pxe_isr, &pxe_irq_chain);
294    if (poll_thread)
295        kill_thread(poll_thread);
296
297    return undi_close.Status;
298}
Note: See TracBrowser for help on using the repository browser.