First ARP implementation ready for testing

This commit is contained in:
Adam Greenwood-Byrne 2021-10-22 01:17:53 +01:00
parent 5abfeb9e30
commit befc45feba
12 changed files with 295 additions and 67 deletions

View file

@ -2,7 +2,7 @@ CFILES = $(wildcard *.c lib/*.c kernel/*.c net/*.c)
SFILES = $(wildcard boot/*.S lib/*.S kernel/*.S)
OFILES = $(CFILES:.c=.o) $(SFILES:.S=.o)
LLVMPATH = /opt/homebrew/opt/llvm/bin
CLANGFLAGS = -Wall -O2 -ffreestanding -nostdlib -mcpu=cortex-a72+nosimd
CLANGFLAGS = -Wall -O0 -ffreestanding -nostdlib -mcpu=cortex-a72+nosimd
all: clean kernel8.img

View file

@ -1,7 +1,7 @@
CFILES = $(wildcard *.c lib/*.c kernel/*.c net/*.c)
SFILES = $(wildcard boot/*.S lib/*.S kernel/*.S)
OFILES = $(CFILES:.c=.o) $(SFILES:.S=.o)
GCCFLAGS = -Wall -O2 -ffreestanding -nostdlib -nostartfiles
GCCFLAGS = -Wall -O0 -ffreestanding -nostdlib -nostartfiles
GCCPATH = ../../gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin
all: clean kernel8.img

View file

@ -1,5 +1,5 @@
void spi_init();
void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size);
unsigned int spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size);
void spi_send(unsigned char *data, unsigned int size);
void spi_recv(unsigned char *data, unsigned int size);
void spi_send_no_selection(unsigned char command);

View file

@ -0,0 +1,201 @@
#include "../net/enc28j60.h"
#include "../include/fb.h"
// Structure for Ethernet header
typedef struct {
uint8_t DestAddrs[6];
uint8_t SrcAddrs[6];
uint16_t type;
} EtherNetII;
// Ethernet packet types
#define ARPPACKET 0x0806
#define IPPACKET 0x0800
// Structure for an ARP Packet
typedef struct {
EtherNetII eth;
uint16_t hardware;
uint16_t protocol;
uint8_t hardwareSize;
uint8_t protocolSize;
uint16_t opCode;
uint8_t senderMAC[6];
uint8_t senderIP[4];
uint8_t targetMAC[6];
uint8_t targetIP[4];
} ARP;
// ARP OpCodes
#define ARPREPLY 0x0002
#define ARPREQUEST 0x0001
// ARP hardware types
#define ETHERNET 0x0001
// MAC address to be assigned to the ENC28J60
uint8_t myMAC[6] = { 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee };
// Router MAC is not known to start with, and requires an ARP reply to find out
uint8_t routerMAC[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
// IP address to be assigned to the ENC28J60
uint8_t deviceIP[4] = { 192, 168, 0, 66 };
// IP Address of the router, whose hardware address we will find using the ARP request
uint8_t routerIP[4] = { 192, 168, 0, 1 };
// HELPER FUNCTIONS
void *memset(void *dest, uint8_t val, uint16_t len)
{
uint8_t *ptr = dest;
while (len-- > 0)
*ptr++ = val;
return dest;
}
void *memcpy(void *dest, const void *src, uint16_t len)
{
uint8_t *d = dest;
const uint8_t *s = src;
while (len--)
*d++ = *s++;
return dest;
}
uint8_t memcmp(void *str1, void *str2, unsigned count)
{
uint8_t *s1 = str1;
uint8_t *s2 = str2;
while (count-- > 0)
{
if (*s1++ != *s2++)
return s1[-1] < s2[-1] ? -1 : 1;
}
return 0;
}
// MAIN FUNCTIONS
void SendArpPacket(uint8_t *targetIP, uint8_t *deviceMAC)
{
/* Parameters:
* targetIP - The target IP Address for the ARP request (the one whose hardware
* address we want)
* deviceMAC - The MAC address of the ENC28J60, i.e. the source MAC for the ARP
* request
*/
ARP arpPacket;
// The source of the packet will be the ENC28J60 MAC address
memcpy(arpPacket.eth.SrcAddrs, deviceMAC, 6);
// The destination is broadcast - a MAC address of FF:FF:FF:FF:FF:FF */
memset(arpPacket.eth.DestAddrs, 0xFF, 6);
arpPacket.eth.type = ARPPACKET;
arpPacket.hardware = ETHERNET;
// We want an IP address resolved
arpPacket.protocol = IPPACKET;
arpPacket.hardwareSize = 0x06; // sizeof(deviceMAC);
arpPacket.protocolSize = 0x04; // sizeof(deviceIP);
arpPacket.opCode = ARPREQUEST;
// Target MAC is set to 0 as it is unknown
memset(arpPacket.targetMAC, 0, 6);
// Sender MAC is the ENC28J60's MAC address
memcpy(arpPacket.senderMAC, deviceMAC, 6);
// The target IP is the IP address we want resolved
memcpy(arpPacket.targetIP, targetIP, 4);
// Check if the last reply has come from an IP address that we want i.e. someone else is already using it
if (!memcmp(targetIP, deviceIP, 4)) {
// Yes, someone is using our IP so set the sender IP to 0.0.0.0
memset(arpPacket.senderIP, 0, 4);
} else {
// No, nobody is using our IP so we can use it confidently
memcpy(arpPacket.senderIP, deviceIP, 4);
}
// Send the packet
ENC_WriteBuffer((unsigned char*)&arpPacket, sizeof(ARP));
}
void arp_test(void)
{
unsigned int tries = 0;
ARP checkPacket;
debugstr("Sending ARP request... ");
SendArpPacket(routerIP, myMAC);
debugstr("done.");
debugcrlf();
debugstr("Waiting for ARP response... ");
debugcrlf();
while (tries < 1000) {
if (ENC_ReadBuffer((unsigned char *)&checkPacket, sizeof(ARP)) == 0) {
continue;
}
if (!memcmp(checkPacket.senderIP, routerIP, 4)) {
// Success! We have found our router's MAC address
memcpy(routerMAC, checkPacket.senderMAC, 6);
debugstr("Router MAC is ");
debughex(routerMAC[0]);
debughex(routerMAC[1]);
debughex(routerMAC[2]);
debughex(routerMAC[3]);
debughex(routerMAC[4]);
debughex(routerMAC[5]);
debugcrlf();
}
tries++;
}
debugstr("Timed out.");
debugcrlf();
}
void init_network(void)
{
ENC_HandleTypeDef handle;
debugstr("Setting MAC address to C0:FF:EE:C0:FF:EE.");
debugcrlf();
handle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
handle.Init.MACAddr = myMAC;
handle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
handle.Init.InterruptEnableBits = 0;
debugstr("Starting network up.");
debugcrlf();
if (!ENC_Start(&handle)) {
debugstr("Could not initialise network card.");
} else {
debugstr("Network card successfully initialised.");
}
debugcrlf();
}

View file

@ -1,4 +1,27 @@
#include "kernel.h"
#include "../include/fb.h"
char *entry_error_messages[] = {
"SYNC_INVALID_EL1t",
"IRQ_INVALID_EL1t",
"FIQ_INVALID_EL1t",
"ERROR_INVALID_EL1T",
"SYNC_INVALID_EL1h",
"IRQ_INVALID_EL1h",
"FIQ_INVALID_EL1h",
"ERROR_INVALID_EL1h",
"SYNC_INVALID_EL0_64",
"IRQ_INVALID_EL0_64",
"FIQ_INVALID_EL0_64",
"ERROR_INVALID_EL0_64",
"SYNC_INVALID_EL0_32",
"IRQ_INVALID_EL0_32",
"FIQ_INVALID_EL0_32",
"ERROR_INVALID_EL0_32"
};
void enable_interrupt_controller() {
REGS_IRQ->irq0_enable_0 = SYS_TIMER_IRQ_1 | SYS_TIMER_IRQ_3;
@ -8,6 +31,14 @@ void disable_interrupt_controller() {
REGS_IRQ->irq0_enable_0 = 0;
}
void show_invalid_entry_message(int type, unsigned long esr, unsigned long address) {
debugstr(entry_error_messages[type]);
debugstr(" ESR: ");
debughex(esr);
debugstr("Addr: ");
debughex(address);
}
void handle_irq() {
unsigned int irq = REGS_IRQ->irq0_pending_0;

View file

@ -67,11 +67,7 @@
mov x0, #\type
mrs x1, esr_el1
mrs x2, elr_el1
// We could pass this to a function to print an error here
// e.g. bl show_invalid_entry_message
//
// For now we'll just hang
bl show_invalid_entry_message
b err_hang
.endm

View file

@ -8,10 +8,10 @@
void initProgress(void)
{
drawRect(0, 0, 301, 50, 0x0f, 0);
drawString(309, 21, "Core 0", 0x0f, 1);
drawString(309, 21, "Core 1", 0x0f, 1);
drawRect(0, 60, 301, 110, 0x0f, 0);
drawString(309, 81, "Core 1", 0x0f, 1);
drawString(309, 81, "Core 2", 0x0f, 1);
drawRect(0, 120, 301, 170, 0x0f, 0);
drawString(309, 141, "Timer 1", 0x0f, 1);
@ -28,21 +28,24 @@ void drawProgress(unsigned int core, unsigned int val) {
if (val > 0) drawRect(1, (60 * core) + 1, (val * 3), (60 * core) + 49, col, 1);
}
void core0_main(void)
{
unsigned int core0_val = 0;
unsigned int c2_done = 0;
while (core0_val <= 100) {
void core2_main(void)
{
unsigned int core2_val = 0;
clear_core2(); // Only run once
while (core2_val <= 100) {
wait_msec(0x100000);
drawProgress(0, core0_val);
core0_val++;
drawProgress(1, core2_val);
core2_val++;
}
debugstr("Core 0 done.");
debugstr("Core 2 done.");
debugcrlf();
irq_disable();
disable_interrupt_controller();
c2_done = 1;
while(1);
}
@ -55,7 +58,7 @@ void core1_main(void)
while (core1_val <= 100) {
wait_msec(0x3FFFF);
drawProgress(1, core1_val);
drawProgress(0, core1_val);
core1_val++;
}
@ -132,37 +135,6 @@ unsigned int HAL_GetTick(void) {
return timer_get_ticks();
}
void init_network(void)
{
ENC_HandleTypeDef handle;
unsigned char macaddr[6];
macaddr[0] = 0xc0;
macaddr[1] = 0xff;
macaddr[2] = 0xee;
macaddr[3] = 0xc0;
macaddr[4] = 0xff;
macaddr[5] = 0xee;
debugstr("Setting MAC address to C0:FF:EE:C0:FF:EE.");
debugcrlf();
handle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
handle.Init.MACAddr = macaddr;
handle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
handle.Init.InterruptEnableBits = 0;
debugstr("Starting network up.");
debugcrlf();
if (!ENC_Start(&handle)) {
debugstr("Could not initialise network card.");
} else {
debugstr("Network card successfully initialised.");
}
debugcrlf();
}
void main(void)
{
fb_init();
@ -172,20 +144,35 @@ void main(void)
initProgress();
// Kick it off on core 1&2
start_core1(core1_main);
start_core2(core2_main);
// Kick off the timers
irq_init_vectors();
enable_interrupt_controller();
irq_enable();
timer_init();
// Test the network card
spi_init();
init_network();
arp_test();
// Kick it off on core 1
// The work is done - wait for timers to get done
start_core1(core1_main);
debugstr("Core 0 done.");
debugcrlf();
// Loop endlessly
while (!c2_done);
core0_main();
// Disable IRQs and loop endlessly
irq_disable();
disable_interrupt_controller();
while(1);
}

View file

@ -49,3 +49,6 @@ unsigned long timer_get_ticks();
void timer_sleep(unsigned int ms);
void HAL_Delay(volatile unsigned int Delay);
unsigned int HAL_GetTick(void);
void init_network(void);
void arp_test(void);

View file

@ -52,7 +52,7 @@ void spi_chip_select(unsigned char chip_select) {
REGS_SPI0->cs = (REGS_SPI0->cs & ~CS_CS) | (chip_select << CS_CS__SHIFT);
}
void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size) {
unsigned int spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size) {
REGS_SPI0->data_length = size;
REGS_SPI0->cs = REGS_SPI0->cs | CS_CLEAR_RX | CS_CLEAR_TX | CS_TA;
@ -89,6 +89,7 @@ void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int
}
REGS_SPI0->cs = (REGS_SPI0->cs & ~CS_TA);
return read_count;
}
void spi_send(unsigned char *data, unsigned int size) {

View file

@ -993,7 +993,7 @@ void ENC_WriteBuffer(void *buffer, uint16_t buflen)
}
/****************************************************************************
* Function: enc_rdbuffer
* Function: ENC_ReadBuffer
*
* Description:
* Read a buffer of data.
@ -1003,15 +1003,17 @@ void ENC_WriteBuffer(void *buffer, uint16_t buflen)
* buflen - The number of bytes to read
*
* Returned Value:
* None
* read_count - Number of bytes received
*
* Assumptions:
* Read pointer is set to the correct address
*
****************************************************************************/
static void enc_rdbuffer(void *buffer, int16_t buflen)
uint8_t ENC_ReadBuffer(void *buffer, uint16_t buflen)
{
uint8_t read_count = 0;
/* Select ENC28J60 chip */
ENC_SPI_Select(true);
@ -1022,9 +1024,11 @@ static void enc_rdbuffer(void *buffer, int16_t buflen)
/* Then read the buffer data */
ENC_SPI_SendBuf(NULL, buffer, buflen);
read_count = ENC_SPI_SendBuf(NULL, buffer, buflen);
/* De-select ENC28J60 chip: done in ENC_SPI_SendBuf callback */
return read_count;
}
/****************************************************************************
@ -1187,7 +1191,7 @@ void ENC_Transmit(ENC_HandleTypeDef *handle)
enc_wrbreg(handle, ENC_ERDPTL, addtTsv4 & 0xff);
enc_wrbreg(handle, ENC_ERDPTH, addtTsv4 >> 8);
enc_rdbuffer(&tsv4, 1);
ENC_ReadBuffer(&tsv4, 1);
regval = enc_rdgreg(ENC_EIR);
if (!(regval & EIR_TXERIF) || !(tsv4 & TSV_LATECOL)) {
break;
@ -1242,7 +1246,7 @@ bool ENC_GetReceivedFrame(ENC_HandleTypeDef *handle)
* and wrap to the beginning of the read buffer as necessary)
*/
enc_rdbuffer(rsv, 6);
ENC_ReadBuffer(rsv, 6);
/* Decode the new next packet pointer, and the RSV. The
* RSV is encoded as:
@ -1281,7 +1285,7 @@ bool ENC_GetReceivedFrame(ENC_HandleTypeDef *handle)
* end_rdbuffer (above).
*/
enc_rdbuffer(handle->RxFrameInfos.buffer, handle->RxFrameInfos.length);
ENC_ReadBuffer(handle->RxFrameInfos.buffer, handle->RxFrameInfos.length);
}
}

View file

@ -98,10 +98,10 @@ void ENC_SPI_Send(uint8_t command);
* Implement SPI buffer send and receive. Must be provided by user code
* param master2slave: data to be sent from host to ENC28J60, can be NULL if we only want to receive data from slave
* param slave2master: answer from ENC28J60 to host, can be NULL if we only want to send data to slave
* retval none
* retval read_count: number of bytes read (if applicable)
*/
void ENC_SPI_SendBuf(uint8_t *master2slave, uint8_t *slave2master, uint16_t bufferSize);
unsigned int ENC_SPI_SendBuf(uint8_t *master2slave, uint8_t *slave2master, uint16_t bufferSize);
/* Exported types ------------------------------------------------------------*/
/** @defgroup ETH_Exported_Types ETH Exported Types
@ -686,6 +686,7 @@ int8_t ENC_RestoreTXBuffer(ENC_HandleTypeDef *handle, uint16_t len);
****************************************************************************/
void ENC_WriteBuffer(void *buffer, uint16_t buflen);
uint8_t ENC_ReadBuffer(void *buffer, uint16_t buflen);
/****************************************************************************
* Function: ENC_Transmit

View file

@ -4,10 +4,14 @@ void ENC_SPI_Select(unsigned char truefalse) {
spi_chip_select(!truefalse); // If it's true, select 0 (the ENC), if false, select 1 (i.e. deselect the ENC)
}
void ENC_SPI_SendBuf(unsigned char *master2slave, unsigned char *slave2master, unsigned short bufferSize) {
unsigned int ENC_SPI_SendBuf(unsigned char *master2slave, unsigned char *slave2master, unsigned short bufferSize) {
unsigned int read_count = 0;
spi_chip_select(0);
spi_send_recv(master2slave, slave2master, bufferSize);
read_count = spi_send_recv(master2slave, slave2master, bufferSize);
spi_chip_select(1); // De-select the ENC
return read_count;
}
void ENC_SPI_Send(unsigned char command) {