diff --git a/src/system/boot/platform/pxe_ia32/network.cpp b/src/system/boot/platform/pxe_ia32/network.cpp index 102a809dbd..9167bfbebb 100644 --- a/src/system/boot/platform/pxe_ia32/network.cpp +++ b/src/system/boot/platform/pxe_ia32/network.cpp @@ -70,12 +70,23 @@ public: private: mac_addr_t fMACAddress; + bool fRxFinished; + PXE_STRUCT * fPxeData; }; UNDI::UNDI() + : fMACAddress() + , fRxFinished(true) + , fPxeData(NULL) { TRACE("UNDI::UNDI\n"); + + fPxeData = pxe_undi_find_data(); + if (!fPxeData) + panic("can't find !PXE structure"); + + TRACE("PXE API entrypoint at %04x:%04x\n", fPxeData->EntryPointSP.seg, fPxeData->EntryPointSP.ofs); } @@ -89,7 +100,61 @@ status_t UNDI::Init() { TRACE("UNDI::Init\n"); - return B_OK; + + PXENV_UNDI_GET_INFORMATION get_info; + PXENV_UNDI_GET_STATE get_state; + PXENV_UNDI_OPEN undi_open; + uint16 res; + + undi_open.OpenFlag = 0; + undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS; + undi_open.R_Mcast_Buf.MCastAddrCount = 0; + + res = call_pxe_bios(fPxeData, UNDI_OPEN, &undi_open); + if (res != 0 || get_state.Status != 0) { + TRACE("PXENV_UNDI_OPEN failed, res %x, status %x\n", res, undi_open.Status); + } + + res = call_pxe_bios(fPxeData, UNDI_GET_STATE, &get_state); + if (res != 0 || get_state.Status != 0) { + TRACE("PXENV_UNDI_GET_STATE failed, res %x, status %x\n", res, get_state.Status); + } else { + switch (get_state.UNDIstate) { + case PXE_UNDI_GET_STATE_STARTED: + TRACE("PXE_UNDI_GET_STATE_STARTED\n"); + break; + case PXE_UNDI_GET_STATE_INITIALIZED: + TRACE("PXE_UNDI_GET_STATE_INITIALIZED\n"); + break; + case PXE_UNDI_GET_STATE_OPENED: + TRACE("PXE_UNDI_GET_STATE_OPENED\n"); + break; + default: + TRACE("unknown undi state 0x%02x\n", get_state.UNDIstate); + break; + } + } + + res = call_pxe_bios(fPxeData, UNDI_GET_INFORMATION, &get_info); + if (res != 0 || get_info.Status != 0) { + TRACE("PXENV_UNDI_GET_INFORMATION failed, res %x, status %x\n", res, get_info.Status); + return B_ERROR; + } + + TRACE("Status = %x\n", get_info.Status); + TRACE("BaseIo = %x\n", get_info.BaseIo); + TRACE("IntNumber = %x\n", get_info.IntNumber); + TRACE("MaxTranUnit = %x\n", get_info.MaxTranUnit); + TRACE("HwType = %x\n", get_info.HwType); + TRACE("HwAddrLen = %x\n", get_info.HwAddrLen); + TRACE("RxBufCt = %x\n", get_info.RxBufCt); + TRACE("TxBufCt = %x\n", get_info.TxBufCt); + + fMACAddress = get_info.CurrentNodeAddress; + + TRACE("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", fMACAddress[0], fMACAddress[1], fMACAddress[2], fMACAddress[3], fMACAddress[4], fMACAddress[5]); + + return B_OK; } @@ -99,11 +164,15 @@ UNDI::MACAddress() const return fMACAddress; } + void * UNDI::AllocateSendReceiveBuffer(size_t size) { TRACE("UNDI::AllocateSendReceiveBuffer, size %ld\n", size); - return 0; + if (size > 0x3000) + return NULL; + + return (void *)0x500; } @@ -117,16 +186,120 @@ UNDI::FreeSendReceiveBuffer(void *buffer) ssize_t UNDI::Send(const void *buffer, size_t size) { - TRACE("UNDI::Send, size %ld\n", size); - return 0; + TRACE("UNDI::Send, buffer %p, size %ld\n", buffer, size); + + hex_dump(buffer, size); + + PXENV_UNDI_TRANSMIT undi_tx; + PXENV_UNDI_TBD undi_tbd; + + undi_tx.Protocol = P_UNKNOWN; + undi_tx.XmitFlag = XMT_DESTADDR; + undi_tx.DestAddr.seg = SEG((char *)buffer + 16); + undi_tx.DestAddr.ofs = OFS((char *)buffer + 16); + undi_tx.TBD.seg = SEG(&undi_tbd); + undi_tx.TBD.ofs = OFS(&undi_tbd); + + undi_tbd.ImmedLength = size; + undi_tbd.Xmit.seg = SEG(buffer); + undi_tbd.Xmit.ofs = OFS(buffer); + undi_tbd.DataBlkCount = 1; + undi_tbd.DataBlock[0].TDPtrType = 1; + undi_tbd.DataBlock[0].TDRsvdByte = 0; + undi_tbd.DataBlock[0].TDDataLen = size; + undi_tbd.DataBlock[0].TDDataPtr.seg = SEG(buffer); + undi_tbd.DataBlock[0].TDDataPtr.ofs = OFS(buffer); + + uint16 res = call_pxe_bios(fPxeData, UNDI_TRANSMIT, &undi_tx); + if (res != 0 || undi_tx.Status != 0) { + TRACE("UNDI_TRANSMIT failed, res %x, status %x\n", res, undi_tx.Status); + return 0; + } + + TRACE("UNDI_TRANSMIT success\n"); + + return size; } ssize_t UNDI::Receive(void *buffer, size_t size) { - TRACE("UNDI::Receive, size %ld\n", size); - return 0; + //TRACE("UNDI::Receive, buffer %p, size %ld\n", buffer, size); + + PXENV_UNDI_ISR undi_isr; + uint16 res; + + if (!fRxFinished) { + TRACE("continue receive...\n"); + + undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr); + if (res != 0 || undi_isr.Status != 0) { + TRACE("PXENV_UNDI_ISR_IN_GET_NEXT failed, res %x, status %x\n", res, undi_isr.Status); + fRxFinished = true; + return 0; + } + + } else { + + undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START; + + res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr); + if (res != 0 || undi_isr.Status != 0) { + TRACE("PXENV_UNDI_ISR_IN_START failed, res %x, status %x\n", res, undi_isr.Status); + return 0; + } + + if (undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS) { +// TRACE("not ours\n"); + return 0; + } + + // send EOI to pic ? + + TRACE("PXENV_UNDI_ISR_OUT_OURS\n"); + + undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; + res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr); + if (res != 0 || undi_isr.Status != 0) { + TRACE("PXENV_UNDI_ISR_IN_PROCESS failed, res %x, status %x\n", res, undi_isr.Status); + return 0; + } + } + + switch (undi_isr.FuncFlag) { + case PXENV_UNDI_ISR_OUT_TRANSMIT: + TRACE("PXENV_UNDI_ISR_OUT_TRANSMIT\n"); + fRxFinished = false; + return 0; + + case PXENV_UNDI_ISR_OUT_RECEIVE: + TRACE("PXENV_UNDI_ISR_OUT_RECEIVE\n"); + TRACE("BufferLength %d\n", undi_isr.BufferLength); + TRACE("FrameLength %d\n", undi_isr.FrameLength); + TRACE("FrameHeaderLength %d\n", undi_isr.FrameHeaderLength); + if (size > undi_isr.BufferLength) + size = undi_isr.BufferLength; + memcpy(buffer, (const void *)(undi_isr.Frame.seg * 16 + undi_isr.Frame.ofs), size); + hex_dump(buffer, size); + fRxFinished = false; + return size; + + case PXENV_UNDI_ISR_OUT_BUSY: + TRACE("PXENV_UNDI_ISR_OUT_BUSY\n"); + fRxFinished = true; + return 0; + + case PXENV_UNDI_ISR_OUT_DONE: + TRACE("PXENV_UNDI_ISR_OUT_DONE\n"); + fRxFinished = true; + return 0; + + default: + TRACE("default!!!\n"); + return 0; + } } @@ -135,14 +308,13 @@ platform_net_stack_init() { TRACE("platform_net_stack_init\n"); - pxe_undi_init(); - UNDI *interface = new(nothrow) UNDI; if (!interface) return B_NO_MEMORY; status_t error = interface->Init(); if (error != B_OK) { + TRACE("platform_net_stack_init: interface init failed\n"); delete interface; return error; } diff --git a/src/system/boot/platform/pxe_ia32/pxe_undi.cpp b/src/system/boot/platform/pxe_ia32/pxe_undi.cpp index 0c812f4c0f..bbe44d7e93 100644 --- a/src/system/boot/platform/pxe_ia32/pxe_undi.cpp +++ b/src/system/boot/platform/pxe_ia32/pxe_undi.cpp @@ -17,11 +17,6 @@ #endif - - -PXE_STRUCT *gPxeData; - - PXE_STRUCT * pxe_undi_find_data() { @@ -35,39 +30,3 @@ pxe_undi_find_data() } return data; } - - -void -pxe_undi_init() -{ - TRACE("pxe_undi_init\n"); - - gPxeData = pxe_undi_find_data(); - if (!gPxeData) - panic("can't find !PXE structure"); - - TRACE("entrypoint at %p\n", *(uint32 *)&gPxeData->EntryPointSP); - - - PXENV_UNDI_GET_INFORMATION get_info; - - memset(&get_info, 0, sizeof(get_info)); - - TRACE("PXENV_UNDI_GET_INFORMATION at %p\n", &get_info); - - uint16 res = call_pxe_bios(gPxeData, UNDI_GET_INFORMATION, &get_info); - - TRACE("res = %04x\n", res); - - TRACE("Status = %x\n", get_info.Status); - TRACE("BaseIo = %x\n", get_info.BaseIo); - TRACE("IntNumber = %x\n", get_info.IntNumber); - TRACE("MaxTranUnit = %x\n", get_info.MaxTranUnit); - TRACE("HwType = %x\n", get_info.HwType); - TRACE("HwAddrLen = %x\n", get_info.HwAddrLen); - TRACE("MAC = %02x:%02x:%02x:%02x:%02x:%02x\n", get_info.CurrentNodeAddress[0], get_info.CurrentNodeAddress[1], - get_info.CurrentNodeAddress[2], get_info.CurrentNodeAddress[3], - get_info.CurrentNodeAddress[4], get_info.CurrentNodeAddress[5] ); - TRACE("RxBufCt = %x\n", get_info.RxBufCt); - TRACE("TxBufCt = %x\n", get_info.TxBufCt); -} diff --git a/src/system/boot/platform/pxe_ia32/pxe_undi.h b/src/system/boot/platform/pxe_ia32/pxe_undi.h index c265e10977..8fe50311c8 100644 --- a/src/system/boot/platform/pxe_ia32/pxe_undi.h +++ b/src/system/boot/platform/pxe_ia32/pxe_undi.h @@ -8,11 +8,17 @@ extern "C" uint16 call_pxe_bios(void *pxe, uint16 opcode, void *param); -void pxe_undi_init(); - - - +#define UNDI_OPEN 0x0006 +#define UNDI_TRANSMIT 0x0008 #define UNDI_GET_INFORMATION 0x000C +#define UNDI_ISR 0x0014 +#define UNDI_GET_STATE 0x0015 + +#define SEG(ptr) ((uint16)(((uint32)(ptr)) >> 4)) +#define OFS(ptr) (((uint16)(ptr)) & 15) + +#define MAC_ADDR_LEN 16 +typedef uint8 MAC_ADDR[MAC_ADDR_LEN]; struct SEGSEL { @@ -21,8 +27,8 @@ struct SEGSEL struct SEGOFF16 { - uint16 seg; uint16 ofs; + uint16 seg; }; struct SEGDESC @@ -54,6 +60,34 @@ struct PXE_STRUCT SEGDESC BC_CodeWrite; }; +struct PXENV_UNDI_MCAST_ADDRESS +{ + #define MAXNUM_MCADDR 8 + uint16 MCastAddrCount; + MAC_ADDR McastAddr[MAXNUM_MCADDR]; +}; + +struct PXENV_UNDI_OPEN +{ + uint16 Status; + uint16 OpenFlag; + uint16 PktFilter; + #define FLTR_DIRECTED 0x0001 + #define FLTR_BRDCST 0x0002 + #define FLTR_PRMSCS 0x0004 + #define FLTR_SRC_RTG 0x0008 + PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +}; + +struct PXENV_UNDI_GET_STATE +{ + #define PXE_UNDI_GET_STATE_STARTED 1 + #define PXE_UNDI_GET_STATE_INITIALIZED 2 + #define PXE_UNDI_GET_STATE_OPENED 3 + uint16 Status; + uint8 UNDIstate; +}; + struct PXENV_UNDI_GET_INFORMATION { uint16 Status; @@ -66,12 +100,75 @@ struct PXENV_UNDI_GET_INFORMATION #define IEEE_TYPE 6 #define ARCNET_TYPE 7 uint16 HwAddrLen; - uint8 CurrentNodeAddress[16]; - uint8 PermNodeAddress[16]; + MAC_ADDR CurrentNodeAddress; + MAC_ADDR PermNodeAddress; SEGSEL ROMAddress; uint16 RxBufCt; uint16 TxBufCt; }; +struct PXENV_UNDI_TRANSMIT +{ + uint16 Status; + uint8 Protocol; + #define P_UNKNOWN 0 + #define P_IP 1 + #define P_ARP 2 + #define P_RARP 3 + uint8 XmitFlag; + #define XMT_DESTADDR 0x0000 + #define XMT_BROADCAST 0x0001 + SEGOFF16 DestAddr; + SEGOFF16 TBD; + uint32 Reserved[2]; +}; + +#define MAX_DATA_BLKS 8 +struct PXENV_UNDI_TBD +{ + uint16 ImmedLength; + SEGOFF16 Xmit; + uint16 DataBlkCount; + struct DataBlk + { + uint8 TDPtrType; + uint8 TDRsvdByte; + uint16 TDDataLen; + SEGOFF16 TDDataPtr; + } DataBlock[MAX_DATA_BLKS]; +}; + +struct PXENV_UNDI_ISR +{ + uint16 Status; + uint16 FuncFlag; + uint16 BufferLength; + uint16 FrameLength; + uint16 FrameHeaderLength; + SEGOFF16 Frame; + uint8 ProtType; + uint8 PktType; +}; + +#define PXENV_UNDI_ISR_IN_START 1 +#define PXENV_UNDI_ISR_IN_PROCESS 2 +#define PXENV_UNDI_ISR_IN_GET_NEXT 3 + +/* One of these will be returned for + PXENV_UNDI_ISR_IN_START +*/ +#define PXENV_UNDI_ISR_OUT_OURS 0 +#define PXENV_UNDI_USR_OUT_NOT_OURS 1 + +/* One of these will be returned for + PXENV_UNDI_ISR_IN_PROCESS and + PXENV_UNDI_ISR_IN_GET_NEXT +*/ +#define PXENV_UNDI_ISR_OUT_DONE 0 +#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 +#define PXENV_UNDI_ISR_OUT_RECEIVE 3 +#define PXENV_UNDI_ISR_OUT_BUSY 4 + +PXE_STRUCT * pxe_undi_find_data(); #endif