mirror of
https://github.com/isometimes/rpi4-osdev
synced 2024-11-09 11:50:40 +00:00
First ARP implementation ready for testing
This commit is contained in:
parent
5abfeb9e30
commit
befc45feba
12 changed files with 295 additions and 67 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
201
part14-ethernet/kernel/arp.c
Normal file
201
part14-ethernet/kernel/arp.c
Normal 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();
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue