aboutsummaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
authorMichael Brown <mcb30@etherboot.org>2007-07-10 04:21:24 +0100
committerMichael Brown <mcb30@etherboot.org>2007-07-10 04:21:24 +0100
commit027fed72c1c76eb3e1a5038d713c074c8ac2034b (patch)
treeef9cf508f2c3136d5be6cb6b9e0918d0e174cf1d /src/arch
parent976a8514cb38f43e506bca2f89112e4900c13d23 (diff)
downloadipxe-027fed72c1c76eb3e1a5038d713c074c8ac2034b.tar.gz
Working code to call the PXE stack from within the ISR.
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/i386/drivers/net/undiisr.S70
-rw-r--r--src/arch/i386/drivers/net/undinet.c41
2 files changed, 92 insertions, 19 deletions
diff --git a/src/arch/i386/drivers/net/undiisr.S b/src/arch/i386/drivers/net/undiisr.S
new file mode 100644
index 00000000..b5838693
--- /dev/null
+++ b/src/arch/i386/drivers/net/undiisr.S
@@ -0,0 +1,70 @@
+#define PXENV_UNDI_ISR 0x0014
+#define PXENV_UNDI_ISR_IN_START 1
+#define PXENV_UNDI_ISR_OUT_OURS 0
+#define PXENV_UNDI_ISR_OUT_NOT_OURS 1
+
+#define IRQ_PIC_CUTOFF 8
+#define ICR_EOI_NON_SPECIFIC 0x20
+#define PIC1_ICR 0x20
+#define PIC2_ICR 0xa0
+
+ .text
+ .arch i386
+ .section ".text16", "ax", @progbits
+ .section ".data16", "aw", @progbits
+ .code16
+
+ .section ".text16"
+ .globl undiisr
+undiisr:
+
+ /* Preserve registers */
+ pushw %ds
+ pushw %es
+ pusha
+
+ /* Issue UNDI API call */
+ movw %cs:rm_ds, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw $undinet_params, %di
+ movw $PXENV_UNDI_ISR, %bx
+ movw $PXENV_UNDI_ISR_IN_START, funcflag
+ pushw %es
+ pushw %di
+ pushw %bx
+ lcall *undinet_entry_point
+ addw $6, %sp
+ cmpw $PXENV_UNDI_ISR_OUT_OURS, funcflag
+ jne chain
+
+ack: /* Record interrupt occurence */
+ incb undiisr_trigger_count
+ /* Send EOI */
+ movb $ICR_EOI_NON_SPECIFIC, %al
+ cmpb $IRQ_PIC_CUTOFF, undiisr_irq
+ jb 1f
+ outb %al, $PIC2_ICR
+1: outb %al, $PIC1_ICR
+ jmp exit
+
+chain: /* Chain to next handler */
+ pushfw
+ lcall *undiisr_next_handler
+
+exit: /* Restore registers and return */
+ popa
+ popw %es
+ popw %ds
+ iret
+
+ .section ".data16"
+undinet_params:
+status: .word 0
+funcflag: .word 0
+bufferlength: .word 0
+framelength: .word 0
+frameheaderlength: .word 0
+frame: .word 0, 0
+prottype: .byte 0
+pkttype: .byte 0
diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c
index 3ed0ed64..c9a610ae 100644
--- a/src/arch/i386/drivers/net/undinet.c
+++ b/src/arch/i386/drivers/net/undinet.c
@@ -146,7 +146,7 @@ static union u_PXENV_ANY __data16 ( undinet_params );
* Used as the indirection vector for all UNDI API calls. Resides in
* base memory.
*/
-static SEGOFF16_t __data16 ( undinet_entry_point );
+SEGOFF16_t __data16 ( undinet_entry_point );
#define undinet_entry_point __use_data16 ( undinet_entry_point )
/**
@@ -245,17 +245,21 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function,
/**
* UNDI interrupt service routine
*
- * The UNDI ISR simply increments a counter (@c trigger_count) and
- * exits.
+ * The UNDI ISR increments a counter (@c trigger_count) and exits.
*/
-extern void undinet_isr ( void );
+extern void undiisr ( void );
-/** Dummy chain vector */
-static struct segoff prev_handler[ IRQ_MAX + 1 ];
+/** IRQ number */
+uint8_t __data16 ( undiisr_irq );
+#define undiisr_irq __use_data16 ( undiisr_irq )
+
+/** IRQ chain vector */
+struct segoff __data16 ( undiisr_next_handler );
+#define undiisr_next_handler __use_data16 ( undiisr_next_handler )
/** IRQ trigger count */
-static volatile uint8_t __text16 ( trigger_count ) = 0;
-#define trigger_count __use_text16 ( trigger_count )
+volatile uint8_t __data16 ( undiisr_trigger_count ) = 0;
+#define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
/** Last observed trigger count */
static unsigned int last_trigger_count = 0;
@@ -275,16 +279,12 @@ static unsigned int last_trigger_count = 0;
static void undinet_hook_isr ( unsigned int irq ) {
assert ( irq <= IRQ_MAX );
+ assert ( undiisr_irq == 0 );
- __asm__ __volatile__ ( TEXT16_CODE ( "\nundinet_isr:\n\t"
- "incb %%cs:%c0\n\t"
- "iret\n\t" )
- : : "p" ( & __from_text16 ( trigger_count ) ) );
-
+ undiisr_irq = irq;
hook_bios_interrupt ( IRQ_INT ( irq ),
- ( ( unsigned int ) undinet_isr ),
- &prev_handler[irq] );
-
+ ( ( unsigned int ) undiisr ),
+ &undiisr_next_handler );
}
/**
@@ -297,8 +297,9 @@ static void undinet_unhook_isr ( unsigned int irq ) {
assert ( irq <= IRQ_MAX );
unhook_bios_interrupt ( IRQ_INT ( irq ),
- ( ( unsigned int ) undinet_isr ),
- &prev_handler[irq] );
+ ( ( unsigned int ) undiisr ),
+ &undiisr_next_handler );
+ undiisr_irq = 0;
}
/**
@@ -310,7 +311,7 @@ static int undinet_isr_triggered ( void ) {
unsigned int this_trigger_count;
/* Read trigger_count. Do this only once; it is volatile */
- this_trigger_count = trigger_count;
+ this_trigger_count = undiisr_trigger_count;
if ( this_trigger_count == last_trigger_count ) {
/* Not triggered */
@@ -424,6 +425,7 @@ static void undinet_poll ( struct net_device *netdev ) {
if ( ! undinet_isr_triggered() )
return;
+#if 0
/* See if this was our interrupt */
memset ( &undi_isr, 0, sizeof ( undi_isr ) );
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
@@ -443,6 +445,7 @@ static void undinet_poll ( struct net_device *netdev ) {
/* If this wasn't our interrupt, exit now */
if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
return;
+#endif
/* Start ISR processing */
undinic->isr_processing = 1;