PERFORCE change 119729 for review
Alexey Tarasov
taleks at FreeBSD.org
Sat May 12 15:52:54 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=119729
Change 119729 by taleks at taleks_th on 2007/05/12 15:52:16
Added modules for working with ARP packets, updated pxe_core (function code and added MAC_ADDR member to pxe_packet structure). Now ISR and receiving cycle are separated. First is done in pxe_isr in vm86 mode (there is also stub pxe_core_isr(), that is for experiments only). Receiving cycle is started by pxe_core_recv_packets() call. Current ideas of packet receiving mechanism may be seen in pxe_arp_ip4mac() function.
Affected files ...
.. //depot/projects/soc2007/taleks-pxe_http/pxe_arp.c#1 add
.. //depot/projects/soc2007/taleks-pxe_http/pxe_arp.h#1 add
.. //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#6 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#6 edit
Differences ...
==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#6 (text+ko) ====
@@ -4,15 +4,15 @@
#include "btxv86.h"
#include "pxe.h"
+#include "pxe_arp.h"
#include "pxe_core.h"
#include "pxe_ip.h"
+#include "pxe_isr.h"
#include "pxe_mem.h"
#include "pxe_mutex.h"
/* PXE API calls here will be made in same way as in pxeboot.
* the only difference - installation of isr, that was not needed in pxe.c.
- * main problem is that, v86 monitors reflects interrupts,
- * we need to change IDT, for correct irq and call pxe_core_isr() from it.
*/
/* NOTE: to think about using of this buffers */
@@ -39,6 +39,7 @@
/* NIC info */
pxe_ipaddr nic_ip = {0};
+MAC_ADDR nic_mac; /* may be init it also by zero? */
/* core packet statistics */
uint32_t packets_dropped = 0;
@@ -168,6 +169,11 @@
/* 3. additional start UNDI */
+ /* saving information about NIC */
+ nic_ip.ip=bootplayer.yip; /* my ip */
+ /* my MAC */
+ pxe_memcpy(&nic_mac, bootplayer.CAddr, MAC_ADDR_LEN);
+
return (1);
}
@@ -185,31 +191,52 @@
pxe_core_call(PXENV_UNDI_GET_INFORMATION);
if (undi_info->Status != 0) {
- printf("pxe_isr_install: failed %x\n", undi_info->Status);
+ printf("pxe_core_install_isr(): failed %x\n", undi_info->Status);
return;
}
- irq=(uint8_t)(undi_info->IntNumber);
+ __pxe_nic_irq=(uint16_t)(undi_info->IntNumber);
#ifdef PXE_DEBUG
- printf("pxe_isr_install() info:\n");
+ printf("pxe_core_install_isr() 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
+
+#ifndef PXE_PMBRANCH
+ /* main branch - ISR is handled in vm86, so installed also there
+ * __isr_install uses __pxe_nic_irq to determine interrupt number.
+ * Well, it may be simplified, cause interrupt number may be got
+ * in this code (as bellow int_num for PM).
+ * TODO: simplify pxe_isr.S code.
+ */
+ bzero(&v86, sizeof(v86));
+
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = (VTOPSEG(__isr_install) << 16) | VTOPOFF(__isr_install);
+ v86.ebx = func;
+ v86int();
+ v86.ctl = V86_FLAGS;
+#else
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);
+ /* PMBRANCH - is subproject, which goal to use ISR in PM
+ * it's not main branch, so just for my own interests
+ * this __isr_install is syscall
+ */
__isr_install(isr_addr, int_num);
+#endif
+
#ifdef PXE_DEBUG
- printf("pxe_isr_install(): success\n");
+ printf("pxe_core_install_isr(): success\n");
#endif
}
@@ -217,6 +244,19 @@
pxe_core_remove_isr()
{
+#ifdef PXE_PMBRANCH
+ /* here must be something */
+#else
+
+ bzero(&v86, sizeof(v86));
+
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = (VTOPSEG(__isr_uninstall) << 16) | VTOPOFF(__isr_uninstall);
+ v86.ebx = func;
+ v86int();
+ v86.ctl = V86_FLAGS;
+
+#endif
}
int
@@ -275,32 +315,37 @@
int
pxe_core_transmit(pxe_packet *pack)
{
+ /* NOTE:all provided data must be in base segment of PXE,
+ * if it's not here, it must be copied here (TO IMPLEMENT)
+ */
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 */
+ tbd.DataBlkCount = 0 ; /* only immediate data */
+
+ undi_send->Protocol = pack->protocol;
+ undi_send->DestAddr.segment = VTOPSEG(pack->dest_mac);
+ undi_send->DestAddr.offset = VTOPOFF(pack->dest_mac);
+ undi_send->TBD.segment = VTOPSEG(&tbd); /* SEGOFF16 to xmit block data*/
+ undi_send->TBD.offset = VTOPOFF(&tbd);
+
+/* NOTE: is it needed? we use only immediate block */
- /* NOTE: if it will work? Check params*/
+/* we've inited undi_info with zero, so two lines below are not needed */
+/* tbd.DataBlk[0].TDRsvdByte = 0; /* reserved */
+/* tbd.DataBlk[1].TDRsvdByte = 0; /* reserved */
tbd.DataBlk[0].TDDataLen=tbd.ImmedLength; /* size of packet*/
+ tbd.DataBlk[0].TDPtrType = 1; /* segment:offset type */
tbd.DataBlk[0].TDDataPtr.segment = VTOPSEG(pack->data);;
tbd.DataBlk[0].TDDataPtr.offset = VTOPOFF(pack->data);;
- 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);
+ pxe_core_call(PXENV_UNDI_TRANSMIT_PACKET);
if (undi_send->Status != 0) {
printf("pxe_core_transmit(): failed %x\n", undi_info->Status);
@@ -414,32 +459,48 @@
return (1);
}
+/* NOTE: now it's handled in real mode ISR, look pxe_isr.S */
void
pxe_core_isr()
{
+
+ if (!pxe_core_is_ours()) {
+ return; /* not ours interrupt, handling is over */
+ }
+}
+
+/*
+ * recieves one packet, if there is any waiting in receiving queue.
+ * in:
+ * none
+ * out:
+ * 0 - there is no packets in receiving queue, or it's not interesting for us.
+ * positive - there were packets in queue and some protocol handler was interested in it.
+ */
+int
+pxe_core_recv_packets()
+{
+
/*
- * 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.
+ * TODO: make it simplier to understand, too many ifs, many lines.
*/
int buffer_size = 0; /* total size of packet*/
int protocol = 0; /* protocol */
- int recieved = 0; /* bytes received to buffer */
+ int received = 0; /* bytes received to buffer */
void *frame_data = NULL;/* pointer to frame data */
int frame_size = 0; /* size of frame */
+ int drop_flag = 0;
+ int processed_packets = 0;
pxe_packet *pack=NULL; /* allocated packet */
pxe_packet dummy_pack; /* temporary struct, used to mimic
* real packet struct
*/
+ if (__pxe_isr_occured == 0) /* there are no packets for us to handle */
+ return (0);
- if (!pxe_core_is_ours()) {
- return; /* not ours interrupt, handling is over */
- }
-
+ __pxe_isr_occured = 0;
t_PXENV_UNDI_ISR *undi_isr =
(t_PXENV_UNDI_ISR *)scratch_buffer;
@@ -447,8 +508,17 @@
bzero(undi_isr, sizeof(*undi_isr));
/* starting packet receive cycle */
- if (0 -- pxe_core_get_packet(PXENV_UNDI_ISR_IN_PROCESS, undi_isr)) {
- return;
+ /* NOTE: pxe_core_recv_packet() name is similar tp pxe_core_get_packet(),
+ * may be renaming is needed.
+ */
+ int func = PXENV_UNDI_ISR_IN_PROCESS;
+
+packet_start:
+
+ drop_flag = 0;
+
+ if (0 == pxe_core_get_packet(func, undi_isr)) {
+ return (processed_packets);
}
buffer_size = undi_isr->BufferLength;
@@ -458,60 +528,75 @@
/* 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 interested in ARP & IP packets */
- /* we are yet not interested in non-ip packets */
+ if ( (protocol == PXE_PROTOCOL_UNKNOWN) || (protocol == PXE_PROTOCOL_RARP) ) {
- if (protocol != PXE_PROTOCOL_IP) {
++packets_dropped;
- return;
+ drop_flag = 1; /* clear queue, receiving all frames of packet */
}
/* checking first fragment, this may help to avoid memory allocation
* and memblock copy
*/
-/* if (buffer_size == frame_size) {*/
+ if (!drop_flag) {
+
+ 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;
+
+ if (protocol == PXE_PROTOCOL_ARP) {
+
+ pxe_arp_protocol(&dummy_pack, PXE_CORE_FRAG, NULL);
+ ++processed_packets;
- pxe_ip *iphdr = (pxe_ip *)frame_data;
+ /* aasume ARP packet always in opne fragment */
+
+ func = PXE_UNDI_ISR_IN_GET_NEXT;
- 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;
+ goto packet_start;
+ }
/* TODO: calc ip checksum */
- if (core_protocol[iphdr->protocol]) {
- if (core_protocol[iphdr->protocol](&dummy_pack,
- PXE_CORE_FRAG, NULL)) {
- return;
- }
- }
-/* }*/
+ if ( (!core_protocol[iphdr->protocol]) ||
+ (!core_protocol[iphdr->protocol](&dummy_pack,
+ PXE_CORE_FRAG, NULL)) ) {
+
+ drop_flag = 1;
+ } else {
+
+ pack = pxe_core_alloc_packet(buffer_size);
- pack = pxe_core_alloc_packet(buffer_size);
+ if (pack == NULL) {
+ pxe_core_flush_packets();
- if (pack == NULL) {
- pxe_core_flush_packets();
+ /* trying to get free packets by sending and dropping */
+ pack = pxe_core_alloc_packet(buffer_size);
- /* trying to get free packets by sending and dropping */
- pack = pxe_core_alloc_packet(buffer_size);
+ /* failed to alloc packet, dropping packet */
+ if (pack == NULL) {
+ ++packets_dropped;
+ drop_flag = 1;
+ }
+ }
- /* failed to alloc packet, dropping packet */
- if (pack == NULL) {
- ++packets_dropped;
- return;
- }
- }
/* pointing user_data to beginning of data.
* It's used by pxe_core_receive() during receiving packet.
*/
- pack->user_data = pack->data;
+ if (pack != NULL)
+ pack->user_data = pack->data;
+ }
+ }
- while (recieved < buffer_size) {
+ while (received < buffer_size) {
if (!pxe_core_get_packet(PXENV_UNDI_ISR_GET_NEXT, undi_isr))
break;
@@ -521,33 +606,46 @@
/* frame_data = undi_isr->Frame.segment << 4 + undi_isr->Frame.offset; */
- pxe_core_recieve(pack, frame_data, frame_size);
+ if (!drop_flag)
+ pxe_core_recieve(pack, frame_data, frame_size);
- recieved += frame_size;
+ received += frame_size;
}
- if (recieved < buffer_size) { /* pxe_core_get_packet() in cycle failed */
- pxe_core_drop(pack);
- return;
+ if (received < buffer_size) { /* pxe_core_get_packet() in cycle failed */
+
+ if (!drop_flag)
+ pxe_core_drop(pack);
+
+ return (processed_packets); /* it's failed, finish receive cycle */
}
- pack->user_data = NULL;
- ++packets_received;
+ if (!drop_flag) {
+
+ pack->user_data = NULL;
+ ++packets_received;
- pxe_ip *iphdr=(pxe_ip *)pack->data;
+ pxe_ip *iphdr=(pxe_ip *)pack->data;
- /* TODO: calc ip checksum */
- pack->protocol = protocol;
+ /* TODO: calc ip checksum */
+ pack->protocol = protocol;
- if (core_protocol[iphdr->protocol]) { /* protocol registered */
- if (core_protocol[iphdr->protocol](pack, PXE_CORE_HANDLE,
- NULL)) {
- return;
+ if ( (!core_protocol[iphdr->protocol]) ||
+ (!core_protocol[iphdr->protocol](pack, PXE_CORE_HANDLE, NULL)) ) {
+ /* protocol not interested in it */
+ pxe_core_drop(pack);
}
}
- /* no such protocol registered or protocol not interested in it */
- pxe_core_drop(pack);
+ ++processed_packets;
+ /* received one or more packets, but need check if there are any others */
+
+ func = PXE_UNDI_ISR_IN_GET_NEXT;
+
+ goto packet_start;
+
+ /* never getting here */
+ return (0);
}
/*
@@ -638,5 +736,12 @@
pxe_get_myip32()
{
- return nic_ip.ip;
+ return nic_ip.ip;
+}
+
+const MAC_ADDR*
+pxe_get_mymac()
+{
+ return &nic_mac;
}
+
==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#6 (text+ko) ====
@@ -35,6 +35,8 @@
void* data; /* pointer to buffer with packet data */
size_t data_size; /* size of packet data */
+
+ const MAC_ADDR *dest_mac; /* destination media address */
void* user_data; /* pointer to user data.
* used by higher level protocols
@@ -64,6 +66,8 @@
/* interrupt handler function, that used to get new packets */
void pxe_core_isr();
+/* recieves one packet if it's waiting */
+int pxe_core_recv_packets();
/* calls PXE/UNDI API, registers of processor must be filled in with
* appropriate values.
@@ -91,9 +95,11 @@
typedef int (*pxe_protocol_call)(pxe_packet *pack, uint8_t function, void *data);
/* registers protocol */
-void pxe_core_register(uint8_t proto, pxe_protocol_call proc);
+void pxe_core_register(uint8_t ip_proto, pxe_protocol_call proc);
/* returns NIC ip */
uint32_t pxe_get_myip32();
+/* returns NIC MAC */
+const MAC_ADDR *pxe_get_mymac();
#endif // PXE_CORE_H_INCLUDED
More information about the p4-projects
mailing list