Date: Fri, 11 May 2007 14:57:30 GMT From: Alexey Tarasov <taleks@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 119672 for review Message-ID: <200705111457.l4BEvUfs055031@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=119672 Change 119672 by taleks@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200705111457.l4BEvUfs055031>