openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

netboot.c (18249B)


      1 /* $Id: //depot/blt/netboot/netboot.c#8 $
      2 **
      3 ** Copyright 1998 Brian J. Swetland
      4 ** All rights reserved.
      5 **
      6 ** Redistribution and use in source and binary forms, with or without
      7 ** modification, are permitted provided that the following conditions
      8 ** are met:
      9 ** 1. Redistributions of source code must retain the above copyright
     10 **    notice, this list of conditions, and the following disclaimer.
     11 ** 2. Redistributions in binary form must reproduce the above copyright
     12 **    notice, this list of conditions, and the following disclaimer in the
     13 **    documentation and/or other materials provided with the distribution.
     14 ** 3. The name of the author may not be used to endorse or promote products
     15 **    derived from this software without specific prior written permission.
     16 **
     17 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 */
     28 #include "string.h"
     29 
     30 #include <blt/conio.h>
     31 
     32 #include "net.h"
     33 #include "boot.h"
     34 
     35 #define NULL ((void *) 0)
     36 
     37 #include "ne2k.h"
     38 #include "io.h"
     39 
     40 snic TheSNIC;
     41 
     42 int nic_addr = 0x300;
     43 
     44 char blah[1500]; /* inbound packet buffer */
     45 
     46 char defaults[] = "ip=0.0.0.0";
     47 
     48 char zz[] = "128.174.38.207";
     49 
     50 char param[80];
     51 
     52 extern char end[];
     53 
     54 #define printf cprintf
     55 
     56 int got_server = 0;
     57 
     58 int id = 1;
     59 
     60 int memsize = 0;
     61 
     62 int reset = 0;
     63 
     64 int got_ip = 0;
     65 char *ipmsg = "";
     66 
     67 unsigned char prom[32];
     68 
     69 unsigned char ip0[8] = { 'i', 'p', '=', 0, 0, 0, 0, 0 };
     70 unsigned char *ip = ip0 + 3;
     71 
     72 unsigned char server_ip[4] = { 0, 0, 0, 0 };
     73 unsigned char server_mac[6] = { 0, 0, 0, 0, 0, 0 };
     74 unsigned short port = 0;
     75 
     76 #define SKIP 0
     77 #define LHS 1
     78 #define RHS 2
     79 
     80 void read_ip(char *s, unsigned char *ip)
     81 {
     82     int i=4;
     83     int v;
     84 
     85     for(i=4;i>0;i--,ip++){
     86         v = 0;
     87         while(*s && *s != '.') {
     88             v = v*10 + *s-'0';
     89             s++;
     90         }
     91         *ip = v;
     92         if(!*s) break;
     93         s++;        
     94     }
     95 }
     96 
     97 void option(char *lhs, char *rhs)
     98 {
     99     if(!strcmp(lhs,"ip")){
    100         read_ip(rhs,ip);
    101         ipmsg = "(manual)";
    102         return;        
    103     }
    104 /*    if(!strcmp(lhs,"server")){
    105         read_ip(rhs,server_ip);        
    106         return;        
    107     }
    108     if(!strcmp(lhs,"gateway")){
    109         read_ip(rhs,gateway_ip);        
    110         return;        
    111     }
    112     if(!strcmp(lhs,"port")){
    113         port = 0;
    114         while(*rhs){
    115             port = port*10 + *rhs - '0';
    116             rhs++;            
    117         }
    118     }    */
    119     printf("netboot: option %s=\"%s\" unknown\n",lhs,rhs);    
    120 }
    121 
    122 void parse(char *p)
    123 {
    124     int state = SKIP;
    125     char *lhs;    
    126     char *rhs;
    127     
    128     while(*p){
    129         switch(state){
    130         case SKIP :
    131             if(*p > ' '){
    132                 lhs = p;
    133                 state = LHS;
    134             } else {
    135                 p++;
    136                 break;                
    137             }
    138         case LHS :
    139             if(*p == '='){
    140                 *p = 0;
    141                 rhs = ++p;
    142                 state = RHS;                
    143             } else {
    144                 p++;                
    145             }
    146             break;
    147         case RHS :
    148             if(*p <= ' '){
    149                 *p = 0;
    150                 option(lhs,rhs);
    151                 state = SKIP;
    152             }
    153             p++;                
    154             break;            
    155         }
    156     }
    157     if(state == RHS){
    158         option(lhs,rhs);
    159     }
    160 }
    161 
    162 #define ESC 27
    163 #define BS 8
    164 #define TAB 9
    165 #define CR 13
    166 
    167 char ScanTable [] =  {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8',
    168                       '9', '0', '-', '=', BS,  TAB, 'q', 'w', 'e', 'r',
    169                       't', 'y', 'u', 'i', 'o', 'p', '[', ']', CR,  ' ',
    170                       'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
    171                       '\'', '~', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n',
    172                       'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '};
    173 char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*',
    174                       '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R',
    175                       'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', CR,  ' ',
    176                       'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
    177                       '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N',
    178                       'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '};
    179 #define LSHIFT 42
    180 #define RSHIFT 54
    181 
    182 char linebuf[80];
    183 int lp;
    184 
    185 
    186 void newline(void)
    187 {
    188     memcpy(linebuf,"netboot> ",9);
    189 
    190     for(lp=9;lp<79;lp++) linebuf[lp]=' ';
    191     linebuf[79]=0;
    192     lp = 9;
    193     con_goto(0,24);
    194     con_puts(linebuf);
    195     
    196 }
    197 
    198 int command(char *cmd)
    199 {
    200     if(cmd[0] == 'g' && cmd[1] == 'o' && cmd[2] == 0) return 1;
    201 
    202     if(cmd[0] == 'b' && cmd[1] == 'o' && cmd[2] == 'o' &&
    203        cmd[3] == 't' && cmd[4] == '='){
    204         char *p = param;
    205         cmd+=5;
    206         while(*cmd) {
    207             *p = *cmd;
    208             cmd++;
    209             p++;
    210         }
    211         *p = 0;
    212         return 0;
    213         
    214     }
    215 
    216     parse(cmd);
    217     
    218     return 0;
    219 }
    220 
    221 int keypress(int key)
    222 {
    223     switch(key){
    224     case ESC:
    225         for(lp=9;lp<79;lp++) linebuf[lp]=' ';
    226         lp = 9;
    227         break;
    228     case CR:
    229         printf("\n");
    230         linebuf[lp]=0;
    231         if(command(linebuf+9)) return 1;
    232         newline();
    233         break;
    234     case BS:
    235         if(lp > 9){
    236             linebuf[lp-1]=' ';
    237             lp--;
    238         }
    239         break;
    240     default:
    241         if(lp < 79){
    242             linebuf[lp]=key;
    243             lp++;
    244         }
    245         break;
    246     }
    247     con_goto(0,24);
    248     con_puts(linebuf);
    249     return 0;
    250 }
    251 
    252 /* keyboard crap */
    253 int console(void)
    254 {
    255     int key;
    256     int shift = 0;
    257     newline();
    258     
    259     for(;;){
    260         while(inb(0x64) & 0x01) {
    261             key = inb(0x60);
    262             
    263             switch(key){
    264             case LSHIFT:
    265             case RSHIFT:
    266                 shift = 1;
    267                 break;
    268             case LSHIFT | 0x80:
    269             case RSHIFT | 0x80:
    270                 shift = 0;
    271                 break;
    272             default:
    273                 if(key & 0x80){
    274                         /* break */
    275                 } else {
    276                     if(key < 59){
    277                         key = shift ? ShiftTable[key] : ScanTable[key];
    278                         if(keypress(key)) return 1;
    279                     }
    280                 }
    281             }
    282         }
    283     }
    284 }
    285 
    286 
    287 
    288 /* end keyboard crap */
    289 packet_buffer *alloc_buffer(uint size)
    290 {
    291     static packet_buffer pb;
    292 
    293     pb.len = size;
    294     pb.page = 0;
    295     pb.ptr = (unsigned char *) blah;    
    296     return &pb;
    297 }
    298 
    299 void free_buffer(packet_buffer *ptr)
    300 {    
    301     int i;
    302     return;
    303 }
    304 
    305 int ticks = 0;
    306 
    307 void idle(void)
    308 {
    309     int i;
    310     for(i=0;i<10000;i++);
    311     ticks++;
    312 }
    313 
    314 int memcmp(const void *dst, const void *src, size_t size)
    315 {
    316     while(size) {
    317         if(*(((unsigned char *) dst)++) != *(((unsigned char *) src)++))
    318             return 1;        
    319         size--;        
    320     }
    321     return 0;    
    322 }
    323 
    324 void *memcpy(void *dst, const void *src, size_t size)
    325 {
    326     while(size) {
    327         *(((unsigned char *) dst)++) = *(((unsigned char *) src)++);
    328         size--;        
    329     }      
    330 	return NULL; /* XXX */
    331 }
    332 
    333 typedef struct 
    334 {
    335     net_ether ether;
    336     net_arp arp;    
    337 } arp_packet;
    338 
    339 typedef struct 
    340 {
    341     net_ether ether;
    342     net_ip ip;    
    343 } ip_packet;
    344 
    345 typedef struct 
    346 {
    347     net_ether ether;
    348     net_ip ip;
    349     net_udp udp;
    350 } udp_packet;
    351 
    352 #include "netboot.h"
    353 
    354 typedef struct 
    355 {
    356     net_ether ether;
    357     net_ip ip;
    358     net_udp udp;
    359     net_boot boot;
    360 } netboot_packet;
    361 
    362 
    363 int ipchksum(unsigned short *ip, int len)
    364 {
    365     unsigned long sum = 0;
    366     len >>= 1;
    367     while (len--) {
    368         sum += *(ip++);
    369         if (sum > 0xFFFF)
    370             sum -= 0xFFFF;
    371     }
    372     return((~sum) & 0x0000FFFF);
    373 }
    374 
    375 static netboot_packet nbr;
    376 
    377 void handle_udp(udp_packet *pkt)
    378 {
    379     packet_buffer pbuf;
    380     
    381 /*    printf("handle_udp: %d -> %d, l=%d, ck=%d\n",
    382            ntohs(pkt->udp.udp_src),
    383            ntohs(pkt->udp.udp_dst),
    384            ntohs(pkt->udp.udp_len),
    385            ntohs(pkt->udp.udp_chk));*/
    386 
    387     if(ntohs(pkt->udp.udp_dst) == NETBOOT_PORT){
    388         netboot_packet *nb = (netboot_packet *) pkt;
    389         unsigned int addr = ntohs(nb->boot.blk) * 1024 + NETBOOT_BASE;
    390         
    391         if(ntohs(nb->boot.cmd) != NETBOOT_CMD_LOAD &&
    392            ntohs(nb->boot.cmd) != NETBOOT_CMD_EXEC){
    393             printf("netboot: invalid command %d\n",
    394                     ntohs(nb->boot.cmd));
    395             return;
    396         }
    397 
    398         if(!got_server){
    399             memcpy(&server_mac,&(pkt->ether.src),6);
    400             memcpy(&server_ip,&(pkt->ip.ip_src),4);
    401             printf("netboot: server %d.%d.%d.%d @ %X:%X:%X:%X:%X:%X\n",
    402                    server_ip[0],server_ip[1],server_ip[2],server_ip[3],
    403                    server_mac[0],server_mac[1],server_mac[2],server_mac[3],
    404                    server_mac[4],server_mac[5]);
    405             got_server = 1;            
    406         }
    407         if(ntohs(nb->boot.cmd) == NETBOOT_CMD_LOAD){
    408 /*            printf("netboot: loading 1024 bytes, net -> 0x%x\n",
    409                    addr);*/
    410             if(addr == NETBOOT_BASE) {
    411                 printf("loading ");
    412             } else {
    413                 printf(".");
    414             }
    415 
    416             memcpy(((void *) addr), &(nb->boot.data), 1024);
    417         }
    418         
    419         memcpy(&(nbr.ether.src),&(prom),6);
    420         memcpy(&(nbr.ether.dst),&(server_mac),6);
    421         nbr.ether.type = ntohs(0x0800);
    422         
    423         memcpy(&(nbr.ip.ip_src),&ip,4);
    424         memcpy(&(nbr.ip.ip_dst),&(server_ip),4);
    425         nbr.ip.ip_hdr_len = 5;
    426         nbr.ip.ip_version = 4;
    427         nbr.ip.ip_tos = 0;
    428         nbr.ip.ip_len = ntohs(20+8+8);
    429         nbr.ip.ip_id = ntohs(id++);
    430         nbr.ip.ip_off = 0;
    431         nbr.ip.ip_ttl = 128;
    432         nbr.ip.ip_proto = IP_PROTO_UDP;
    433         nbr.ip.ip_chk = 0;
    434         nbr.ip.ip_chk = ipchksum(&(nbr.ip),sizeof(net_ip));
    435         
    436         nbr.udp.udp_dst = pkt->udp.udp_src;
    437         nbr.udp.udp_src = pkt->udp.udp_dst;
    438         nbr.udp.udp_chk = 0;
    439         nbr.udp.udp_len = ntohs(8 + 4);
    440 
    441         nbr.boot.cmd = htons(NETBOOT_CMD_ACK);
    442         nbr.boot.blk = nb->boot.blk;
    443         pbuf.ptr = (unsigned char *) &nbr;
    444         pbuf.page = 0;
    445         pbuf.len = 14 + 20 + 8 + 4;
    446 
    447         if(ntohs(nb->boot.cmd) == NETBOOT_CMD_EXEC){
    448             boot_dir *bd = (boot_dir *) NETBOOT_BASE;            
    449             volatile void (*start)(int, char *, boot_dir *) =
    450                 bd->bd_entry[1].be_code_ventr +
    451                 0x1000 + NETBOOT_BASE;
    452             
    453             printf("\nnetboot: executing at 0x%x\n", (int) start);
    454             start(memsize, param[0] ? param : (char *) ip0, bd);            
    455             asm("hlt");           
    456         } else {
    457             nic_send_packet(&TheSNIC, &pbuf);
    458         }
    459 
    460     }
    461 }
    462 
    463 
    464 void handle_ip(ip_packet *pkt)
    465 {
    466     unsigned char *src = (unsigned char *) &( pkt->ip.ip_src );
    467     unsigned char *dst = (unsigned char *) &( pkt->ip.ip_dst );
    468     int i;
    469     
    470 /*    printf("handle_ip: IP: %d.%d.%d.%d -> %d.%d.%d.%d\n",
    471            src[0],src[1],src[2],src[3],
    472            dst[0],dst[1],dst[2],dst[3]);*/
    473 
    474     if(!memcmp(dst,ip,4)){        
    475         if(ipchksum(&(pkt->ip),sizeof(net_ip))) {
    476             return;
    477         }        
    478 /*        printf("handle_ip: for me? whoah!\n");*/
    479         if(pkt->ip.ip_proto == IP_PROTO_UDP) handle_udp((udp_packet *) pkt);
    480         
    481     }
    482     
    483 }
    484 
    485 void print_arp(unsigned char *p);
    486 
    487 
    488 unsigned char bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
    489 unsigned char zilch[6] = { 0, 0, 0, 0, 0, 0 };
    490 
    491 void issue_rarp_request(void)
    492 {
    493     arp_packet req;
    494     packet_buffer pbuf;            
    495 
    496     req.ether.type = htons(0x8035);    
    497     memcpy(&(req.ether.src),prom,6);
    498     memcpy(&(req.ether.dst),bcast,6);
    499     req.arp.arp_hard_type = htons(1);
    500     req.arp.arp_prot_type = htons(0x0800);
    501     req.arp.arp_hard_size = 6;
    502     req.arp.arp_prot_size = 4;            
    503     req.arp.arp_op = htons(RARP_OP_REQUEST);
    504     memcpy(&(req.arp.arp_enet_sender),prom,6);
    505     memcpy(&(req.arp.arp_ip_sender),bcast,4);
    506     memcpy(&(req.arp.arp_enet_target),prom,6);
    507     memcpy(&(req.arp.arp_ip_target),bcast,4);
    508 
    509     pbuf.ptr = (unsigned char *) &req;
    510     pbuf.page = 0;
    511     pbuf.len = sizeof(arp_packet);            
    512     nic_send_packet(&TheSNIC, &pbuf);                   
    513 }
    514 
    515 void handle_rarp(arp_packet *req)
    516 {
    517     unsigned char *x;
    518     
    519     if(htons(req->arp.arp_op) == RARP_OP_REPLY){
    520         if(!memcmp(&(req->arp.arp_enet_target),prom,6)){
    521             if(memcmp(&(req->arp.arp_ip_target),ip,4)){
    522                 x = &(req->arp.arp_ip_target);
    523                 ip[0] = x[0];
    524                 ip[1] = x[1];
    525                 ip[2] = x[2];
    526                 ip[3] = x[3];
    527                 got_ip = 1;
    528                 ipmsg = "(RARP'd)";
    529                 reset = 1;
    530             }
    531         }
    532     }
    533 }
    534 
    535 void handle_arp(arp_packet *req)
    536 {
    537     if(htons(req->arp.arp_op) == ARP_OP_REQUEST){
    538         if(!memcmp(&(req->arp.arp_ip_target),ip,4)){
    539             packet_buffer pbuf;            
    540             arp_packet resp;            
    541 /*            printf("handle_arp: IS the one!\n");*/
    542 /*            printf("handle_arp: replying to arp request\n");            */
    543             memcpy(&(resp.ether.src),prom,6);
    544             memcpy(&(resp.ether.dst),&(req->ether.src),6);
    545             resp.ether.type = htons(0x0806);
    546             resp.arp.arp_hard_type = htons(1);
    547             resp.arp.arp_prot_type = htons(0x0800);
    548             resp.arp.arp_hard_size = 6;
    549             resp.arp.arp_prot_size = 4;            
    550             resp.arp.arp_op = htons(ARP_OP_REPLY);
    551             memcpy(&(resp.arp.arp_enet_sender),prom,6);
    552             memcpy(&(resp.arp.arp_ip_sender),ip,4);
    553             memcpy(&(resp.arp.arp_enet_target),&(req->arp.arp_enet_sender),6);
    554             memcpy(&(resp.arp.arp_ip_target),&(req->arp.arp_ip_sender),4);
    555 /*            print_arp((unsigned char *) &(resp.arp));*/
    556             pbuf.ptr = (unsigned char *) &resp;
    557             pbuf.page = 0;
    558             pbuf.len = sizeof(arp_packet);            
    559             nic_send_packet(&TheSNIC, &pbuf);            
    560         } else {
    561 /*            printf("handle_arp: NOT the one.\n");            */
    562         }
    563         return;        
    564     }
    565 }
    566 
    567 void print_arp(unsigned char *p)
    568 {
    569 #ifdef ARP_DEBUG
    570     net_arp *arp = (net_arp *) p;
    571     unsigned char *b;    
    572     unsigned short t;
    573     
    574     printf("  ARP: ");
    575     t = htons(arp->arp_op);
    576     if(t == ARP_OP_REQUEST) printf("req ");
    577     else if(t == ARP_OP_REPLY) printf("rep ");
    578     else printf("??? ");
    579 
    580     b = (unsigned char *) &(arp->arp_enet_sender);
    581     printf("source:  %X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]);
    582     b = (unsigned char *) &(arp->arp_ip_sender);
    583     printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]);
    584 
    585     printf("  ARP:     target:  ");    
    586     
    587     b = (unsigned char *) &(arp->arp_enet_target);
    588     printf("%X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]);
    589     b = (unsigned char *) &(arp->arp_ip_target);
    590     printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]);    
    591 #endif
    592 }
    593 
    594 
    595 void receive(packet_buffer *packet)
    596 {
    597     unsigned char *b = packet->ptr;
    598     int i;
    599 
    600     if(b[12] == 0x80 && b[13] == 0x35) {
    601         handle_rarp((arp_packet *) b);
    602         return;
    603     }
    604     if(b[12] != 0x08) return; /* ignore non IP/ARP packets */
    605     
    606     if(b[12] == 0x08 && b[13] == 0x06) {
    607 /*        print_arp(b+14);*/
    608         handle_arp((arp_packet *) b);
    609         return;
    610     }
    611 
    612     if(b[12] == 0x08 && b[13] == 0x00) {
    613         handle_ip((ip_packet *) b);
    614         return;
    615     } 
    616 }
    617 
    618 void find_8390(int *addr);
    619 
    620 extern char *blagh;
    621 
    622 void main(int mem)
    623 {
    624     int i,mono;
    625     int nh;    
    626     char buf[128];
    627     int snic_irq = 3;    
    628     char *x;
    629 	
    630     memsize = mem;
    631     param[0] = 0;
    632     
    633     mono = (((*((unsigned char *) 0x410)) & 0x30) == 0x30);
    634 
    635     parse(defaults);
    636     
    637 	find_8390(&nic_addr);
    638 	
    639 	ipmsg = "(default)";
    640 	ip[0] = ip[1] = ip[2] = ip[3] = 10;
    641 	
    642     for(;;){
    643         reset = 0;
    644         
    645         TheSNIC.iobase = 0;
    646         nic_init(&TheSNIC, nic_addr, prom, NULL);
    647 
    648         con_start( mono ? 0xB0000 : 0xB8000);
    649 
    650         if(!mono){
    651             con_fgbg(CON_WHITE, CON_BLUE /*WHITE,CON_BLUE*/);
    652         }
    653 /*              01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
    654 		printf("\n");
    655 		printf("    ##   ##  ######  ######  ######    #####    #####   ######\n");
    656 		printf("    ###  ##  ##        ##    ##   ##  ##   ##  ##   ##    ##\n");
    657 		printf("    ## # ##  #####     ##    ######   ##   ##  ##   ##    ##\n");
    658 		printf("    ##  ###  ##        ##    ##   ##  ##   ##  ##   ##    ##     Version 1.5\n");
    659 		printf("    ##   ##  ######    ##    ######    #####    #####     ##     " __DATE__);
    660 		
    661         if(!mono){
    662             con_fgbg(CON_WHITE,CON_BLACK);
    663         }
    664         printf("\n\n\n");
    665 		printf("0x00090000 - bootloader start\n");
    666         printf("0x%x - bootloader end\n", (int) end);
    667         printf("0x00100000 - target load address\n");
    668         printf("0x%x - top of memory\n",mem);
    669         printf("\n");
    670         
    671         printf("NE2000 @ 0x%S (%X:%X:%X:%X:%X:%X)\n", nic_addr,
    672                prom[0],prom[1],prom[2],prom[3],prom[4],prom[5]);    
    673         
    674         printf("ip = %d.%d.%d.%d %s\n",ip[0],ip[1],ip[2],ip[3],
    675                ipmsg);
    676         if(param[0]) printf("boot = \"%s\"\n",param);
    677         
    678         nic_register_notify(&TheSNIC,receive);
    679         
    680         nic_start(&TheSNIC,0);
    681         
    682         printf("\nready. (ESC for console)\n");
    683 
    684         if(!got_ip){
    685             issue_rarp_request();
    686             issue_rarp_request();
    687             issue_rarp_request();
    688         }
    689 		
    690         while(!reset){
    691             nic_isr(&TheSNIC);
    692             if(inb(0x64) & 0x01) {
    693                 if(inb(0x60) == 1){
    694                     con_fgbg(CON_YELLOW,CON_BLACK);
    695                     if(console()) break;
    696                 }
    697             }
    698         }
    699         nic_stop(&TheSNIC);            
    700     }
    701 }