os-workshop

same materials and sample source for RV32 OS projects
git clone http://frotz.net/git/os-workshop.git
Log | Files | Refs

netboot.c (4567B)


      1 // Copyright 2022, Brian Swetland <swetland@frotz.net>
      2 // Licensed under the Apache License, Version 2.0
      3 
      4 #include <string.h>
      5 #include <stdio.h>
      6 
      7 #include <hw/riscv.h>
      8 #include <hw/context.h>
      9 #include <hw/intrinsics.h>
     10 #include <hw/debug.h>
     11 
     12 #include <hw/platform.h>
     13 #include <hw/litex.h>
     14 
     15 #include <net/ipv6.h>
     16 #include <netboot.h>
     17 
     18 #include "boot.h"
     19 
     20 // we expect the supervisor program to be in memory after the end of the bootloader
     21 #define SVC_ENTRY (DRAM_BASE + BOOTLOADER_SIZE)
     22 
     23 #define uart_rd(a) io_rd32(UART0_BASE + LX_UART_ ## a)
     24 #define uart_wr(a,v) io_wr32(UART0_BASE + LX_UART_ ## a, v)
     25 #define eth_rd(a) io_rd32(ETHMAC_BASE + LX_ETHMAC_ ## a)
     26 #define eth_wr(a,v) io_wr32(ETHMAC_BASE + LX_ETHMAC_ ## a, v)
     27 
     28 void halt_peripherals(void) {
     29 	eth_wr(WR_EV_ENABLE, 0);
     30 	eth_wr(RD_EV_ENABLE, 0);
     31 }
     32 
     33 const char *nodename = "device";
     34 
     35 void query_reply(void *replyto) {
     36 	netboot_msg_t *msg = replyto;
     37 	unsigned len = snprintf((void*)msg->db, NB_DATA_MAX, "name=%s", nodename);
     38 	msg->cmd = NB_CMD_STATUS;
     39 	msg->arg = NB_OK;
     40 	net_tx_udp_reply(replyto, msg, NB_MSG_MIN + len + 1, NB_PORT_CTRL);
     41 }
     42 
     43 void pkt_rx_udp(void *data, unsigned len, unsigned port, int mcast) {
     44 	netboot_msg_t* msg = data;
     45 	if ((len < NB_MSG_MIN) || (len > NB_MSG_MAX) || (msg->magic != NB_MAGIC)) {
     46 		return;
     47 	}
     48 
     49 	if (port == NB_PORT_QUERY) {
     50 		unsigned nlen = strlen(nodename);
     51 		// query port only replies to valid queries that match
     52 		if ((msg->cmd != NB_CMD_QUERY) ||
     53 			(len != (nlen + NB_MSG_MIN)) ||
     54 			(memcmp(msg->db, nodename, nlen))) {
     55 			return;
     56 		}
     57 		query_reply(data);
     58 		return;
     59 	}
     60 	if (port != NB_PORT_CTRL) {
     61 		return;
     62 	}
     63 
     64 	switch (msg->cmd) {
     65 	case NB_CMD_QUERY:
     66 		xputc('Q');
     67 		query_reply(data);
     68 		return;
     69 	case NB_CMD_WRITE:
     70 		xputc('.');
     71 		// TODO: apply range limits?
     72 		memcpy((void*) msg->arg, msg->db, len - NB_MSG_MIN);
     73 		msg->cmd = NB_CMD_STATUS;
     74 		msg->arg = NB_OK;
     75 		net_tx_udp_reply(data, msg, NB_MSG_MIN, NB_PORT_CTRL);
     76 		return;
     77 	case NB_CMD_EXEC: {
     78 		xputc('!');
     79 		uint32_t entry = msg->arg;
     80 		msg->cmd = NB_CMD_STATUS;
     81 		msg->arg = NB_OK;
     82 		net_tx_udp_reply(data, msg, NB_MSG_MIN, NB_PORT_CTRL);
     83 
     84 		csr_write(CSR_MSTATUS, PRIV_S << MSTATUS_MPP_SHIFT);
     85 		xprintf("\n\n[ execution starts at 0x%08x ]\n\n", entry);
     86 		exit_mode_m(0, 0, entry, 0);
     87 		return;
     88 	}
     89 	default:
     90 		xputc('E');
     91 		msg->cmd = NB_CMD_STATUS;
     92 		msg->arg = NB_ERR_BADCMD;
     93 		net_tx_udp_reply(data, msg, NB_MSG_MIN, NB_PORT_CTRL);
     94 		break;
     95 	}
     96 }
     97 
     98 uint8_t rxbuf[1536] = { 0, };
     99 
    100 void eth_rx(uint8_t *rxb, unsigned rxlen) {
    101 	if (rxlen > 1534) return;
    102 	memcpy(rxbuf + 2, rxb, rxlen);
    103 	net_rx_eth(rxbuf, rxlen + 2);
    104 }
    105 
    106 
    107 static unsigned txslot;
    108 
    109 void eth_tx(void *txb, unsigned txlen) {
    110 	if (txlen > 1534) return;
    111 
    112 	while (eth_rd(RD_READY) != 1) ;
    113 
    114 	memcpy((void*)(ETHMAC_SRAM_BASE + ETHMAC_SLOT_SIZE * (ETHMAC_RX_SLOTS + txslot)), txb, txlen);
    115 
    116 	eth_wr(RD_SLOT, txslot);
    117 	eth_wr(RD_LEN, txlen);
    118 	eth_wr(RD_START, 1);
    119 
    120 	txslot ^= 1;
    121 }
    122 
    123 void eth_init(void) {
    124 	eth_wr(WR_EV_ENABLE, 0);
    125 	eth_wr(RD_EV_ENABLE, 0);
    126 
    127 	eth_wr(WR_EV_PENDING, 1);
    128 	eth_wr(RD_EV_PENDING, 1);
    129 
    130 	txslot = 0;
    131 	eth_wr(RD_SLOT, txslot);
    132 
    133 	eth_wr(WR_EV_ENABLE, 1);
    134 	eth_wr(RD_EV_ENABLE, 1);
    135 }
    136 
    137 void eth_handle_rx(void) {
    138 	if (eth_rd(WR_EV_PENDING) & 1) {
    139 		uint32_t slot = eth_rd(WR_SLOT);
    140 		uint8_t *rxb = (void*) (ETHMAC_SRAM_BASE + ETHMAC_SLOT_SIZE * slot);
    141 		eth_rx(rxb, eth_rd(WR_LEN));
    142 		eth_wr(WR_EV_PENDING, 1);
    143 	}
    144 }
    145 
    146 void netboot(void) {
    147 	uint8_t mac[6] = { 0x42,0x42,0x10,0x20,0x30,0x40 };
    148 	net_init(mac);
    149 	eth_init();
    150 	for (;;) {
    151 		eth_handle_rx();
    152 	}
    153 }
    154 
    155 void mach_exception_handler(eframe_t *ef) {
    156 	xprintf("\n** MACHINE EXCEPTION **\n");
    157 	xprint_m_exception(ef);
    158 	xprintf("\nHALT\n");
    159 	for (;;) ;
    160 }
    161 
    162 // interrupts and exceptions to delegate to supervisor mode
    163 #define INT_LIST (INTb_SVC_SW|INTb_SVC_TIMER|INTb_SVC_EXTERN)
    164 //#define EXC_LIST (EXCb_ECALL_UMODE)
    165 #define EXC_LIST (0xFFFF)
    166 
    167 void start(uint32_t hartid, uint32_t fdt) {
    168 	xprintf("\n** Frobozz Magic (Network) Bootloader v0.2 **\n\n");
    169 
    170 	int qemu = (csr_read(CSR_MVENDORID) == 0);
    171 
    172 	// set mach exception vector and stack pointer
    173 	csr_write(CSR_MTVEC, ((uintptr_t) mach_exception_entry) );
    174 
    175 	// use the free ram below the supervisor entry as our exception stack
    176 	csr_write(CSR_MSCRATCH, SVC_ENTRY);
    177 
    178 	// QEMU currently emulates memory protection, which we must appease
    179 	if (qemu) {
    180 		// U/S allow access to all memory
    181 		csr_write(CSR_PMPCFG(0), PMP_CFG_A_TOR | PMP_CFG_X | PMP_CFG_W | PMP_CFG_R);
    182 		csr_write(CSR_PMPADDR(0), 0xFFFFFFFF);
    183 	}
    184 
    185 	// delegate interrupts and exceptions
    186 	csr_set(CSR_MIDELEG, INT_LIST);
    187 	csr_set(CSR_MEDELEG, EXC_LIST);
    188 
    189 	netboot();
    190 }
    191