📄 halether.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
halether.c
Abstract:
Platform specific code for debug ethernet services (debug messages,
kernel debugger, text shell (PPSH)). These functions are all called
from ethdbg.lib. They are non-preemptible, and cannot make any system calls.
Functions:
Notes:
--*/
#include <windows.h>
#include <nkintr.h>
#include <ethdbg.h>
#include <halether.h>
#include <hal.h>
#include <PCIreg.h>
#include "pc.h"
#include "bootarg.h"
#include "oalintr.h"
int __cdecl _inp (unsigned short);
int __cdecl _outp (unsigned short, int);
//
// Function pointers to the support library functions of the currently installed debug ethernet controller.
//
PFN_EDBG_INIT pfnEDbgInit;
PFN_EDBG_INIT_DMABUFFER pfnEDbgInitDMABuffer;
PFN_EDBG_ENABLE_INTS pfnEDbgEnableInts;
PFN_EDBG_DISABLE_INTS pfnEDbgDisableInts;
PFN_EDBG_GET_PENDING_INTS pfnEDbgGetPendingInts;
PFN_EDBG_GET_FRAME pfnEDbgGetFrame;
PFN_EDBG_SEND_FRAME pfnEDbgSendFrame;
PFN_EDBG_READ_EEPROM pfnEDbgReadEEPROM;
PFN_EDBG_WRITE_EEPROM pfnEDbgWriteEEPROM;
PFN_EDBG_SET_OPTIONS pfnEDbgSetOptions;
PFN_EDBG_CURRENT_PACKET_FILTER pfnCurrentPacketFilter;
PFN_EDBG_MULTICAST_LIST pfnMulticastList;
#define ETHDMA_BUFFER_BASE 0x80200000 // MUST MATCH CONFIG.BIB
#define ETHDMA_BUFFER_SIZE 0x00020000 // 128K DMA Buffer
#define EDBG_PHYSICAL_MEMORY_START (0x801DC000) // MUST MATCH CONFIG.BIB
static BOOT_ARGS *pBootArgs;
// Buffer for receiving frames into.
UCHAR RcvBuf[1500];
extern DWORD EdbgDebugZone;
USHORT wLocalMAC[3]; // Saved copy of the mac address
// Well known DHCP ports for use with UDP
#define DHCP_SERVER_PORT 0x4300
#define DHCP_CLIENT_PORT 0x4400
// We retry more than Odo since CEPC BIOS's take longer to boot.
#define MAX_BOOTME_CNT 20
#define BOOTME_INTERVAL 3
#define PLATFORM_STRING "CEPC"
typedef struct __VendorId // NIC vendor ID.
{
USHORT wVenId; // Vendor Id
USHORT wDevId; // Device Id
ULONG dwUpperMAC; // first 3 bytes of ethernet address
UCHAR Type; // NIC type (EDBG_ADAPTER_xxx)
UCHAR *szAbbrev; // Vendor name abbreviation
} VENDORID, *PVENDORID;
static const VENDORID VendorIds[] =
{
// VenId DevId MAC Type Name
// -------------------------------------------------------
{0x0000, 0x0000, 0x004033, EDBG_ADAPTER_NE2000, "AD" }, // Addtron Tech (ISA)
{0x1050, 0x0940, 0x004005, EDBG_ADAPTER_NE2000, "LS" }, // LinkSys
{0x1050, 0x0940, 0x002078, EDBG_ADAPTER_NE2000, "LS" }, // LinkSys
{0x10EC, 0x8029, 0x00C0F0, EDBG_ADAPTER_NE2000, "KS" }, // Kingston
{0x10EC, 0x8129, 0x000000, EDBG_ADAPTER_RTL8139, "RT" }, // RealTek (Lanner)
{0x10EC, 0x8139, 0x00900B, EDBG_ADAPTER_RTL8139, "RT" }, // RealTek (Lanner)
{0x10EC, 0x8139, 0x00D0C9, EDBG_ADAPTER_RTL8139, "RT" }, // RealTek (Lanner)
{0x10EC, 0x8139, 0x00E04C, EDBG_ADAPTER_RTL8139, "RT" }, // RealTek (Advantech)
{0x100B, 0x0020, 0x00A0CC, EDBG_ADAPTER_DP83815, "NG" } // Netgear
};
#define NUM_VENDORIDS (sizeof(VendorIds)/sizeof(VENDORID))
#ifdef IMGSHAREETH
BOOL bNewFilter = FALSE; // User mode --> Kernel mode to set new filter.
DWORD dwFilter; // The filter..
BOOL bNewMulticast = FALSE; // User mode --> Kernel mode for new list
DWORD dwNoOfEntry;
BOOL ucMultiAddr[8][6]; // The new list..
// VMINI assumes 8 multicast list entry..
//
#endif
static void
itoa10(
int n,
char s[]
)
{
int i = 0;
// Get absolute value of number
unsigned int val = (unsigned int)((n < 0) ? -n : n);
// Extract digits in reverse order
do {
s[i++] = (val % 10) + '0';
} while (val /= 10);
// Add sign if number negative
if (n < 0) s[i++] = '-';
s[i--] = '\0';
// Reverse string
for (n = 0; n < i; n++, i--) {
char swap = s[n];
s[n] = s[i];
s[i] = swap;
}
}
static DWORD
UpperDWFromMAC(EDBG_ADDR * pAddr)
{
DWORD ret;
//
// The WORDs in wMAC field are in net order, so we need to do some
// serious shifting around.
// A hex ethernet address of 12 34 56 78 9a bc is stored in wMAC array as
// wMAC[0] = 3412, wMAC[1] = 7856, wMAC[2] = bc9a.
// The 4 byte return value should look like 0x00123456
//
ret = (pAddr->wMAC[0] & 0x00ff) << 16;
ret |= pAddr->wMAC[0] & 0xff00;
ret |= pAddr->wMAC[1] & 0x00ff;
return ret;
}
void
CreateDeviceName(EDBG_ADDR *pMyAddr, char *szBuf)
{
int i;
DWORD dwUpperMAC = UpperDWFromMAC(pMyAddr);
// If a device name was passed up by the bootloader, use it.
//
if ((pBootArgs->dwVersionSig == BOOT_ARG_VERSION_SIG) &&
strlen(pBootArgs->szDeviceNameRoot))
strncpy(szBuf, pBootArgs->szDeviceNameRoot, EDBG_MAX_DEV_NAMELEN);
else
strcpy(szBuf, PLATFORM_STRING);
szBuf += strlen(szBuf);
for (i=0;i<NUM_VENDORIDS;i++) {
if (dwUpperMAC == VendorIds[i].dwUpperMAC) {
strcat(szBuf,VendorIds[i].szAbbrev);
szBuf += strlen(szBuf);
break;
}
}
itoa10(((pMyAddr->wMAC[2]>>8) | ((pMyAddr->wMAC[2] & 0x00ff) << 8)), szBuf);
}
#define IPSTATE_NONE 0
#define IPSTATE_GOTIP 1
#define IPSTATE_ARP 2
#define IPSTATE_ARPED 3
#define IPSTATE_RETRY 4
#define MAX_DHCP_RETRY 3
/* OEMEthInit
*
* Initialization routine - called from EdbgInit() to perform platform specific
* HW init. The CEPC platform uses either an SMC 91C94 Ethernet controller or
* an NE2000 compatible adapter (NSC 8390 ethernet controller).
*
* Return Value:
* Return TRUE if init is successful, FALSE if error.
*/
BOOL
OEMEthInit(EDBG_ADAPTER *pAdapter)
{
pBootArgs = (BOOT_ARGS *) ((ULONG)(*(PBYTE *)BOOT_ARG_PTR_LOCATION) | 0x80000000);
// Some parameters included in boot args for future use, make sure these aren't set
switch (pBootArgs->ucEdbgAdapterType) {
case EDBG_ADAPTER_NE2000:
pfnEDbgInit = NE2000Init;
pfnEDbgInitDMABuffer = NULL;
pfnEDbgEnableInts = NE2000EnableInts;
pfnEDbgDisableInts = NE2000DisableInts;
pfnEDbgGetPendingInts = NE2000GetPendingInts;
pfnEDbgGetFrame = NE2000GetFrame;
pfnEDbgSendFrame = NE2000SendFrame;
pfnEDbgReadEEPROM = NE2000ReadEEPROM;
pfnEDbgWriteEEPROM = NE2000WriteEEPROM;
break;
case EDBG_ADAPTER_RTL8139:
pfnEDbgInit = RTL8139Init;
pfnEDbgInitDMABuffer = RTL8139InitDMABuffer;
pfnEDbgEnableInts = RTL8139EnableInts;
pfnEDbgDisableInts = RTL8139DisableInts;
pfnEDbgGetPendingInts = RTL8139GetPendingInts;
pfnEDbgGetFrame = RTL8139GetFrame;
pfnEDbgSendFrame = RTL8139SendFrame;
pfnEDbgReadEEPROM = RTL8139ReadEEPROM;
pfnEDbgWriteEEPROM = RTL8139WriteEEPROM;
break;
case EDBG_USB_RNDIS:
EdbgOutputDebugString(" RNDIS Edbg!\r\n");
pfnEDbgInit = HostMiniInit;
pfnEDbgEnableInts = RndisEnableInts;
pfnEDbgDisableInts = RndisDisableInts;
pfnEDbgGetPendingInts = RndisGetPendingInts;
pfnEDbgGetFrame = RndisEDbgGetFrame;
pfnEDbgSendFrame = RndisEDbgSendFrame;
pfnEDbgReadEEPROM = NULL;
pfnEDbgWriteEEPROM = NULL;
pfnEDbgSetOptions = RndisSetOptions;
pfnCurrentPacketFilter= RndisCurrentPacketFilter;
pfnMulticastList = RndisMulticastList;
break ;
default:
EdbgOutputDebugString("Unsupported debug Ethernet parameters - adapter: %u, IRQ:%u\n",
pBootArgs->ucEdbgAdapterType, pBootArgs->ucEdbgIRQ);
return (FALSE);
}
// Initialize NIC DMA buffer, if required.
//
if (pfnEDbgInitDMABuffer)
{
if (!pfnEDbgInitDMABuffer(ETHDMA_BUFFER_BASE, ETHDMA_BUFFER_SIZE))
{
EdbgOutputDebugString("ERROR: Failed to initialize Ethernet controller DMA buffer.\r\n");
return FALSE;
}
}
pAdapter->Addr=pBootArgs->EdbgAddr;// Inherit Eth address from Bootloader first.
if (!pfnEDbgInit((BYTE *) pBootArgs->dwEdbgBaseAddr,1,pAdapter->Addr.wMAC) )
return (FALSE);
// Check the MAC address - this can be invalid if the switches are set wrong.
if ( !pAdapter->Addr.wMAC[0] && !pAdapter->Addr.wMAC[1] && !pAdapter->Addr.wMAC[2] ) {
EdbgOutputDebugString("Invalid Ethernet address read from the debug ethernet controller, check switch settings\n");
return (FALSE);
}
// Save out local mac address.
memcpy ((char *)wLocalMAC, pAdapter->Addr.wMAC, sizeof(wLocalMAC));
EdbgOutputDebugString("Debug Ethernet card initialized, MAC Address:%B:%B:%B:%B:%B:%B\r\n",
pAdapter->Addr.wMAC[0] & 0x00FF, pAdapter->Addr.wMAC[0] >> 8,
pAdapter->Addr.wMAC[1] & 0x00FF, pAdapter->Addr.wMAC[1] >> 8,
pAdapter->Addr.wMAC[2] & 0x00FF, pAdapter->Addr.wMAC[2] >> 8 );
#if defined(IMGSHAREETH)
VBridgeInit();
VBridgeKSetLocalMacAddress((char *)wLocalMAC);
#endif
// Fill in our SYSINTR value for the EDBG subsystem. Since we have limited IRQ
// resources, just run in polled mode unless otherwise configured.
if ( pBootArgs->ucEdbgIRQ )
pAdapter->SysIntrVal = OEMTranslateIrq(pBootArgs->ucEdbgIRQ);
else
pAdapter->SysIntrVal = EDBG_SYSINTR_NOINTR;
pAdapter->Addr.dwIP = pBootArgs->EdbgAddr.dwIP;
pAdapter->DHCPLeaseTime = pBootArgs->DHCPLeaseTime;
pAdapter->EdbgFlags = pBootArgs->EdbgFlags;
// Enable filtering of broadcast packets (all except ARP packets) to reduce overhead. We still have
// to take an interrupt, but the driver can quickly determine whether a packet may be discarded without
// having to copy all the data from the chip. Note that we cannot turn this option on until DHCP is
// done processing, since some DHCP servers return responses in broadcast frames.
#ifndef IMGSHAREETH
if (pAdapter->Addr.dwIP)
pfnEDbgSetOptions(OPT_BROADCAST_FILTERING);
#endif
return (TRUE);
}
/* OEMEthEnableInts
*
* Turn on HW interrupts. Return TRUE if interrupts supported, or FALSE
* to run in polling mode for all clients.
*/
void
OEMEthEnableInts()
{
pfnEDbgEnableInts();
}
/* OEMEthDisableInts
*
* Disable HW interrupts.
*/
void
OEMEthDisableInts()
{
pfnEDbgDisableInts();
}
#ifdef IMGSHAREETH
/* ProcessVMiniSend()
*
* This routine drains the pending VMINI TX.
*
*/
void
ProcessVMiniSend(void)
{
PBYTE pVMiniData;
DWORD dwVMiniDataLength;
////////////////////////////////////////////////////////////////////////////
// Handle the filter if we need to..
//
if (bNewFilter && pfnCurrentPacketFilter)
{
bNewFilter = FALSE;
pfnCurrentPacketFilter(dwFilter);
}
//
// Handle new multicast list..
//
if (bNewMulticast && pfnMulticastList)
{
bNewMulticast = FALSE;
pfnMulticastList(
(PUCHAR)ucMultiAddr,
dwNoOfEntry);
}
////////////////////////////////////////////////////////////////////////////
// Consume all the client packets.
//
while (VBridgeKGetOneTxBuffer(&pVMiniData, &dwVMiniDataLength) == TRUE)
{
pfnEDbgSendFrame (pVMiniData, dwVMiniDataLength);
VBridgeKGetOneTxBufferComplete(pVMiniData);
}
} // ProcessVMiniSend()
#endif
/* OEMEthISR
*
* ISR routine, called by EDBG IST when Ethernet controller interrupts. Also
* called in polling mode, to check for received data.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -