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 }