PERFORCE change 119672 for review
Alexey Tarasov
taleks at FreeBSD.org
Fri May 11 14:57:31 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=119672
Change 119672 by taleks at taleks_th on 2007/05/11 14:56:54
Updated ISR handler for real/vm86 mode, udated pxe_core code with PXE API calls.
Affected files ...
.. //depot/projects/soc2007/taleks-pxe_http/btx_mod/btx/btx.S#4 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#5 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#5 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_icmp.c#4 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_icmp.h#3 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_isr.S#2 edit
Differences ...
==== //depot/projects/soc2007/taleks-pxe_http/btx_mod/btx/btx.S#4 (text+ko) ====
@@ -402,7 +402,6 @@
popl %es # data
movl %esp,%ebx # Stack frame
movl $dmpfmt,%esi # Dump format string
- movl $MEM_BUF,%edi # Buffer
pushl %edi # Dump to
call dump # buffer
popl %esi # and
@@ -707,10 +706,14 @@
jmp int_hw # V86 int 0x70
push $0x71 # Int 0x29: IRQ9
jmp int_hw # V86 int 0x71
- push $0x72 # Int 0x2a: IRQ10
- jmp int_hw # V86 int 0x72
+# push $0x72 # Int 0x2a: IRQ10
+# jmp int_hw # V86 int 0x72
+# just to test, my NIC's IRQ
+ nop
+ jmp user_isr_call
push $0x73 # Int 0x2b: IRQ11
jmp int_hw # V86 int 0x73
+ jmp user_isr_call
push $0x74 # Int 0x2c: IRQ12
jmp int_hw # V86 int 0x74
push $0x75 # Int 0x2d: IRQ13
@@ -874,58 +877,101 @@
* will be run user_isr_call, which role is to run provided function
* in user space.
*/
-intx30.2: xorl %eax,%eax # clear eax
+
+
+intx30.2:
+ cli
+ pushl %edi
+ pushl %ebx
+ pushw %ds
+ pushw %dx
+
+ pushl %ss # Set up
+ popl %ds # registers
+
+
+ movl $MEM_USR,%ebx # User base address
+ addl 0x18(%esp,1),%ebx # getting user stack head
+ addl $0x04, %ebx # first parameter
+
+ movl (%ebx), %eax
+ movw 0x2(%ebx), %dx
+ xchgw %dx, %bx
/*
* updating call gate
*/
- mov gdtdesc,%edi # calculating descriptors entry
- add $SEL_CALLGATE,%edi # pointing callgate selector
-
- popl %eax # got 32bit offset to handler
-
- movw %ax,(%edi) # +0: store offset 00..15
- shr $0x10,%eax # getting high word
- add $0x06,%edi # +6:
- mov %ax,(%edi) # handler offset 16..31
+ movl $callgate, %edi
+ movw %ax, (%edi) # +0: store offset 00..15
+ shr $0x10 ,%eax # getting high word
+ movw %ax, 0x06(%edi) # +6: handler offset 16..31
/*
* installing handler
- */
- xor %ax,%ax # clear ax
- pop %ax # getting interrupt number
- mov $0x08, %bl #
- mulb %bl #
-
- mov $MEM_IDT,%di # point to IDT.
- add %ax,%di # calculate entry
-
- mov $SEL_SCODE,%dh # supervisor code selector
- mov user_isr_call,%ax # tramp address
-
- mov $0x8e,%dl # i386+ interrupt gate, DPL=0
-
- mov %ax,(%edi) # 0: handler offset 0..15
- mov %dh,0x2(%edi) # +2: dest selector
- # +4: 000:word_count=0
- mov %dl,0x5(%edi) # +5: P:DPL:type
- # +6: handler offset 16..31
+ */
+# xorl %eax, %eax # clear
+# movw %bx, %ax # getting interrupt number
+# mov $0x08, %bl # calculating offset
+# mulb %bl # to IDT entry
+# #
+# movl $MEM_IDT,%edi # base address of IDT.
+# addl %eax, %edi # calculate address of entry
+#
+# movb $SEL_SCODE, %dh # supervisor code selector
+# mov user_isr_call, %ax # tramp address
+# movb $0x8e, %dl # i386+ interrupt gate, DPL=0
+#
+# movw %ax,(%edi) # 0: handler offset 0..15
+# movb %dh, 0x2(%edi) # +2: dest selector
+# # +4: 000:word_count=0
+# movb %dl, 0x5(%edi) # +5: P:DPL:type
+ # +6: handler offset 16..31
/*
* NOTE: it seems nothing else must be done
*/
+
+ popw %dx
+ popw %ds
+ popl %ebx
+ popl %edi
+ sti
iret # return from syscall
user_isr_call:
/*
* NOTE: isr must use lret to return and restore SS, ESP, CS, EIP.
*/
- push %ds # saving ds
- mov $SEL_UDATA,%ax #
- mov %ax,%ds # setting it to userspace data
- # cs is updated from selector
+ pushl %ds # saving ds
+ pushl %edi
+ movl $SEL_SDATA, %eax #
+ movl %eax, %ds
+
+ movl $callgate, %edi
+ movw (%edi), %ax
+ popl %edi
+
+ cmpw $0x0000, %ax
+ je isr_ret
+
+# movl $SEL_UDATA, %eax
+# movl %eax, %ds
+# pushl %ds
+# popl %fs
+# pushl %fs
+# popl %gs
+# pushl %gs
+# popl %es
+
+
lcall $SEL_CALLGATE,$0x00000000 # far call via callgate selector
# offset is ignored
- pop %ds # restore data segment
+
+isr_ret:
+
+
+ popl %ds
+
iret # return from interrupt handler
+
/*
* Dump structure [EBX] to [EDI], using format string [ESI].
@@ -1159,8 +1205,10 @@
.word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
+# .word 0xffff,MEM_USR,0xba00,0xcf# SEL_UCODE
+# .word 0xffff,MEM_USR,0xb200,0xcf# SEL_UDATA
.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
- .word 0x5, 0x0, 0xec00,0x0 # SEL_CALLGATE
+callgate: .word 0x0, SEL_UCODE,0xec00,0x0 # SEL_CALLGATE
gdt.1:
/*
* Pseudo-descriptors.
@@ -1228,6 +1276,7 @@
.ascii "ss:esp" # "ss:esp="
.byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
.asciz "BTX halted\n" # End
+#save_esp: .word 0x0000,0x0000
/*
* End of BTX memory.
==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#5 (text+ko) ====
@@ -174,7 +174,43 @@
void
pxe_core_install_isr()
{
+ t_PXENV_UNDI_GET_INFORMATION *undi_info =
+ (t_PXENV_UNDI_GET_INFORMATION *)scratch_buffer;
+
+#ifdef PXE_DEBUG
+ printf("pxe_isr_install() called\n");
+#endif
+ bzero(undi_info, sizeof(*undi_info));
+
+ pxe_core_call(PXENV_UNDI_GET_INFORMATION);
+
+ if (undi_info->Status != 0) {
+ printf("pxe_isr_install: failed %x\n", undi_info->Status);
+ return;
+ }
+
+ irq=(uint8_t)(undi_info->IntNumber);
+
+#ifdef PXE_DEBUG
+ printf("pxe_isr_install() info:\n");
+ printf("IRQ: %d\n", undi_info->IntNumber);
+ printf("Base io: %d\n", undi_info->BaseIo);
+ printf("MTU: %d\n", undi_info->MaxTranUnit);
+ printf("RX buffer queue: %d\n", undi_info->RxBufCt);
+ printf("TX buffer queue: %d\n", undi_info->TxBufCt);
+ printf("installing ISR\n");
+#endif
+ uint16_t int_num=(irq < 8) ? irq + 0x08 : irq + 0x68;
+
+ caddr_t isr_addr=pxe_isr-__base;
+ printf("setting interrupt: %d for 0x%x (0x%x, base = 0x%x)\n",
+ int_num, pxe_isr, isr_addr, __base);
+ __isr_install(isr_addr, int_num);
+
+#ifdef PXE_DEBUG
+ printf("pxe_isr_install(): success\n");
+#endif
}
void
@@ -239,10 +275,39 @@
int
pxe_core_transmit(pxe_packet *pack)
{
+ t_PXENV_UNDI_TRANSMIT *undi_send =
+ (t_PXENV_UNDI_TRANSMIT *)scratch_buffer;
+
+ bzero(undi_send, sizeof(*undi_info));
+
+ /* media address */
+ uint_8_t media_addr[6] = {0,0,0,0,0,0};
+
+ t_PXENV_UNDI_TBD tbd;
+ tbd.ImmedLength = pack->data_size; /* packet length */
+ tbd.Xmit.segment = VTOPSEG(pack->data); /* immediate transmit buffer */
+ tbd.Xmit.offset = VTOPOFF(pack->data);
+ tbd.DataBlkCount = 1 ; /* one block */
+ tbd.DataBlk[0].TDPtrType = 1; /* segment:offset type */
+ tbd.DataBlk[0].TDRsvdByte = 0; /* reserved */
+
+ /* NOTE: if it will work? Check params*/
+ tbd.DataBlk[0].TDDataLen=tbd.ImmedLength; /* size of packet*/
+ tbd.DataBlk[0].TDDataPtr.segment = VTOPSEG(pack->data);;
+ tbd.DataBlk[0].TDDataPtr.offset = VTOPOFF(pack->data);;
- /* UNDI transmit ip packet call*/
+ undi_send->Protocol = P_IP;
+ undi_send->DestAddr.segment = VTOPSEG(media_addr);
+ undi_send->DestAddr.offset = VTOPOFF(media_addr);
+
+ pxe_core_call(PXENV_UNDI_GET_INFORMATION);
+
+ if (undi_send->Status != 0) {
+ printf("pxe_core_transmit(): failed %x\n", undi_info->Status);
+ return (0);
+ }
- return (0);
+ return (1);
}
/* flushes pending, aborted, wrong and etc packets */
@@ -267,9 +332,98 @@
return (1);
}
+/*
+ * checks if interrupt handler was executed for our NIC
+ * (in case of shared IRQs)
+ * in:
+ * none
+ * out:
+ * 0 - not our interrupt, return
+ * 1 - our, must handle receiving
+ */
+int
+pxe_core_is_our()
+{
+ /*
+ * NOTE: best idea to do it in real mode interrupt handler,
+ * The PXE specs suggest fast interrupt handling,
+ * starting handler thread and returning
+ */
+ t_PXENV_UNDI_ISR *undi_isr =
+ (t_PXENV_UNDI_ISR *)scratch_buffer;
+
+ bzero(undi_isr, sizeof(*undi_isr));
+
+ undi_isr->FuncFlag=PXENV_UNDI_ISR_IN_START;
+ pxe_core_call(PXENV_UNDI_ISR);
+
+ if (undi_isr->Status != 0) { /* pxe_core_call() failed */
+ /* pretend, failed cause not ours interrupt */
+ return (0);
+ }
+
+ if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_OURS)
+ return (1);
+
+ return (0);
+}
+
+/*
+ 0 - failed
+ 1 - success
+*/
+int
+pxe_core_get_packet(int func, t_PXENV_UNDI_ISR *undi_isr )
+{
+
+ undi_isr->FuncFlag = func;
+
+ while(1) { /* cycle to handle busy flag */
+
+ undi_isr->Status = 0;
+
+ pxe_core_call(PXENV_UNDI_ISR);
+
+ if (undi_isr->Status != 0) {
+ /* something gone wrong */
+ return (0);
+ }
+
+ if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) {
+ /* nothing to de */
+ break;
+ }
+
+ if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) {
+ /* NIC is busy, wait */
+ sleep(1);
+ continue;
+ }
+
+ if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECIEVE) {
+ /* that's what we are waiting for */
+ break;
+ }
+
+ if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
+ /* transmitted packet */
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
void
pxe_core_isr()
{
+ /*
+ * NOTE: code here it must be redone to separate receiving thread
+ * and interrupt handler.
+ * in fact real mode ISR implements pxe_core_is_ours()
+ * and modifies __pxe_isr_occured, which must be checked
+ * in receiving queue.
+ */
int buffer_size = 0; /* total size of packet*/
int protocol = 0; /* protocol */
int recieved = 0; /* bytes received to buffer */
@@ -282,9 +436,27 @@
* real packet struct
*/
- /*
- * TODO: UNDI get buffer size & etc
- */
+ if (!pxe_core_is_ours()) {
+ return; /* not ours interrupt, handling is over */
+ }
+
+
+ t_PXENV_UNDI_ISR *undi_isr =
+ (t_PXENV_UNDI_ISR *)scratch_buffer;
+
+ bzero(undi_isr, sizeof(*undi_isr));
+
+ /* starting packet receive cycle */
+ if (0 -- pxe_core_get_packet(PXENV_UNDI_ISR_IN_PROCESS, undi_isr)) {
+ return;
+ }
+
+ buffer_size = undi_isr->BufferLength;
+ protocol = undi_isr->ProtType;
+ frame_size = undi_isr->FrameLength;
+
+/* how to get in this address from userspace, which starts at 0xa800?*/
+/* frame_data = undi_isr->Frame.segment << 4 + undi_isr->Frame.offset; */
/* we are yet not interested in non-ip packets */
@@ -298,25 +470,26 @@
* and memblock copy
*/
-/* if (buffer_size==frame_size) {
+/* if (buffer_size == frame_size) {*/
- pxe_ip *iphdr = (pxe_ip *)frame_data;
+ pxe_ip *iphdr = (pxe_ip *)frame_data;
- dummy_pack.protocol = protocol;
- dummy_pack.state = PXE_PACKET_STATE_USING;
- dummy_pack.data = frame_data;
- dummy_pack.data_size = frame_size;
- dummy_pack.user_data = NULL;
+ dummy_pack.protocol = protocol;
+ dummy_pack.state = PXE_PACKET_STATE_USING;
+ dummy_pack.data = frame_data;
+ dummy_pack.data_size = frame_size;
+ dummy_pack.user_data = NULL;
- /* TODO: calc ip checksum /
+ /* TODO: calc ip checksum */
- if (core_protocol[iphdr->protocol]) {
- if (core_protocol[iphdr->protocol](&dummy_pack, PXE_CORE_FRAG,
- NULL)) {
+ if (core_protocol[iphdr->protocol]) {
+ if (core_protocol[iphdr->protocol](&dummy_pack,
+ PXE_CORE_FRAG, NULL)) {
return;
}
}
-*/
+/* }*/
+
pack = pxe_core_alloc_packet(buffer_size);
if (pack == NULL) {
@@ -339,17 +512,25 @@
pack->user_data = pack->data;
while (recieved < buffer_size) {
- /*
- * UNDI get frame
- */
+
+ if (!pxe_core_get_packet(PXENV_UNDI_ISR_GET_NEXT, undi_isr))
+ break;
+
+ frame_size = undi_isr->FrameLength;
+/* how to get in this address from userspace, which starts at 0xa800?*/
+/* frame_data = undi_isr->Frame.segment << 4 + undi_isr->Frame.offset; */
- frame_size=0;
pxe_core_recieve(pack, frame_data, frame_size);
recieved += frame_size;
}
+ if (recieved < buffer_size) { /* pxe_core_get_packet() in cycle failed */
+ pxe_core_drop(pack);
+ return;
+ }
+
pack->user_data = NULL;
++packets_received;
==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#5 (text+ko) ====
==== //depot/projects/soc2007/taleks-pxe_http/pxe_icmp.c#4 (text+ko) ====
==== //depot/projects/soc2007/taleks-pxe_http/pxe_icmp.h#3 (text+ko) ====
==== //depot/projects/soc2007/taleks-pxe_http/pxe_isr.S#2 (text+ko) ====
@@ -39,6 +39,7 @@
chained_irq_seg: .word 0x0000 # stores original handler for interrupt
original_mask: .byte 0x00 # stores interrupt mask
+save_int_mask: .byte 0x00 # stores interrupt mask
base_ds: .word 0x0000 # data segment
s_pxenv_undi_isr: .word 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
@@ -57,6 +58,11 @@
.word 0x0000 # PXE API entry point segment
add $6, %sp # restore stack
ret
+/*
+ * NOTES to think:
+ * 1. it seems BTX programms PIC with ICW4 = 2 (Auto EOI), so half of this code may be omited
+ * 2. do we really need to save chained handler
+ */
/*
* Adopted from Intel PXE SDK
@@ -98,19 +104,23 @@
* ACK to each hardware PIC needing ACK.
*/
- movw __pxe_nic_irq, %ax # getting irq number
- movb %al, %dl # moving it to dl
- movb $I8259_EOI, %al # set EOI control word
-
- cmpb $0x8, %dl # is IRQ8-IRQ15?
- jb pxe_isr.master # no, use pic1
-
- movw $I8259_AT_INTR_CTRL_REG,%dx # send EOI to PIC2
- outb %al, %dx #
-
-pxe_isr.master: movw $I8259_EOI_REG, %dx # send EOI to master
- outb %al, %dx #
-
+/*
+ * hope AEOI'programmed pic will do it work itself
+ **
+ * movw __pxe_nic_irq, %ax # getting irq number
+ * movb %al, %dl # moving it to dl
+ * movb $I8259_EOI, %al # set EOI control word
+ *
+ * cmpb $0x8, %dl # is IRQ8-IRQ15?
+ * jb pxe_isr.master # no, use pic1
+ *
+ * movw $I8259_AT_INTR_CTRL_REG,%dx # send EOI to PIC2
+ * outb %al, %dx #
+ *
+ * pxe_isr.master:
+ * movw $I8259_EOI_REG, %dx # send EOI to master
+ * outb %al, %dx #
+ */
pxe_isr.exit: popw %es # restore affected registers
popw %di #
popw %dx #
@@ -126,42 +136,44 @@
sti # enable interrupts
pushf # push flags
-# pushw %es
-
-# movw chained_irq_off+2, %ax
-# movw %ax, %es
-# movw chained_irq_off, %bx
- movl chained_irq_off, %eax
-
-# call %es:(%bx) # call chained handler
- call *%eax
-
-# popw %es
+/*
+ * here is calling of chained interrupt handler. Don't think it' srelly needed now
+ **
+ * pushw %es
+ * movw chained_irq_off+2, %ax
+ * movw %ax, %es
+ * movw chained_irq_off, %bx
+ * call %es:(%bx) # call chained handler
+ * popw %es
+ */
-
/*
* If say "not my interrupt" by passing control to next in handler list, may
* end up invoking the BIOS, which will turn off the interrupt at the PIC.
* In case this happens, on return from next-handler call, see if must restore.
* This only executes when an interrupt is fielded which is not ours to handle.
*/
- movw $I8259_PC_INTR_MASK_REG, %dx # use master
- movw __pxe_nic_irq, %bx
- cmpb $0x8, %bl # is IRQ8-IRQ15?
- jb pxe_isr.1 # no
- movw $I8259_AT_INTR_MASK_REG, %dx # use PIC2
-
-pxe_isr.1: movb original_mask, %bl # restore original mask
- inb %dx, %al
- notb %bl
- testb %bl, %al
- jz pxe_isr.2
- notb %bl
- andb %bl, %al
- outb %al, %dx
-
+/*
+ * rely all PIC related actions on BTX
+ **
+ * movw $I8259_PC_INTR_MASK_REG, %dx # use master
+ * movw __pxe_nic_irq, %bx
+ * cmpb $0x8, %bl # is IRQ8-IRQ15?
+ * jb pxe_isr.1 # no
+ * movw $I8259_AT_INTR_MASK_REG, %dx # use PIC2
+ *
+ * pxe_isr.1: movb save_int_mask, %bl # get saved mask
+ * inb %dx, %al
+ * notb %bl
+ * testb %bl, %al
+ * jz pxe_isr.2
+ *
+ * notb %bl
+ * andb %bl, %al
+ * outb %al, %dx
+ */
pxe_isr.2:
jmp pxe_isr.exit
@@ -202,8 +214,11 @@
popw %es # restore affected register
-# call pxe_mask_int # TODO: implement
-
+/*
+ * Masking is not our task
+ **
+ * call mask_int # masking
+ */
popf # restore flags
popw %cx # restore affected registers
@@ -254,7 +269,11 @@
isr_remove.3: movl chained_irq_off, %eax # getting old chained handler
movl %eax, %es:(%bx) # restore it
-# call pxe_unmask_int # TODO: implement
+/*
+ * Forget about unmasking for now
+ **
+ * call unmask_int # unmasking
+ */
isr_remove.fin:
movl $0x0, chained_irq_off
@@ -262,3 +281,90 @@
popf
clc
ret
+
+/*
+ * Adopted from Intel PXE SDK
+ * masks hardware interrupt
+ */
+mask_int: pushw %ax # saving all affected
+ pushw %cx # registers
+ pushw %dx #
+
+ movw __pxe_nic_irq, %bx # getting irq number
+ cmpw $0x7, %bx # see if this master PIC
+ jbe mask_int.master # yes, it's PIC1
+
+ subw $0x08, %bx # getting 3bits value
+ movw $I8259_AT_INTR_MASK_REG, %dx # setting PIC register to PIC2
+ jmp mask_int.1
+
+mask_int.master:
+ movw I8259_PC_INTR_MASK_REG, %dx # setting master PIC register
+
+mask_int.1: movw %bx, %cx
+ andw $0x07, %cx
+ movw $0x1, %bl
+ shlb %cl, %bl
+ andb original_mask, %bl # get the original bit for this irq
+
+ pushf # saving FLAGS register
+ cli # stop interrupts (IF=0)
+ inb %dx, %al
+
+ orb %bl, %al # change the bit to the orig value
+ outb %al, %dx
+ popw %ax # popping FLAGS
+
+ testw $0x200, %ax # checking interrupt flag
+ jz mask_int.2 # IF=1
+ sti # starting interrupts
+mask_int.2:
+ popw %dx
+ popw %cx
+ popw %ax
+ ret
+
+/*
+ * Adopted from Intel PXE SDK
+ * unmasks hardware interrupt
+ */
+unmask_int: pushw %ax # save all affected
+ pushw %cx # registers
+ pushw %dx #
+
+ movw __pxe_nic_irq, %bx # getting irq number
+ cmpw $0x07, %bx # is it PIC2?
+ jbe unmask_int.master # no, it's master
+
+ subw $0x08, %bx
+ mov $I8259_AT_INTR_MASK_REG, %dx # setting slave PIC register
+ jmp unmask_int.2
+
+unmask_int.master:
+ mov $I8259_PC_INTR_MASK_REG, %dx # setting master PIC register
+
+unmask_int.2: movw %bx, %cx
+ andw $0x07, %cx # masking first 3 bits
+ movb $0x01, %bl #
+ shlb %cl, %bl # shifting 1 bit to left
+ notb %bl
+
+ movb %bl, save_int_mask # saving mask
+
+ pushf # saving FLAGS register
+ cli
+
+ inb %dx, %al # sending control word
+ movb %al, original_mask # saving mask
+ andb %bl, %al # and it with saved
+ outb %al, %dx # out result
+
+ popw %ax # popping flags
+ testw $0x200, %ax # IF==1 ?
+ jz unmask_int.3 # yes
+ sti # set IF=1
+
+unmask_int.3: popw %dx # restore all affected registers
+ popw %cx #
+ popw %ax #
+ ret
More information about the p4-projects
mailing list