1/* 2 * Copyright 2003-2006, Axel D��rfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2006, Marcus Overhagen, marcus@overhagen.de. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7#include "bios.h" 8#include "pxe_undi.h" 9#include "network.h" 10 11#include <KernelExport.h> 12#include <boot/partitions.h> 13#include <boot/platform.h> 14#include <boot/vfs.h> 15#include <boot/stdio.h> 16#include <boot/stage2.h> 17#include <boot/net/NetStack.h> 18#include <boot/net/RemoteDisk.h> 19#include <util/kernel_cpp.h> 20#include <util/KMessage.h> 21 22#include <string.h> 23 24#define TRACE_DEVICES 25#ifdef TRACE_DEVICES 26# define TRACE(x...) dprintf(x) 27#else 28# define TRACE(x...) 29#endif 30 31 32//extern unsigned char* gBuiltinBootArchive; 33//extern long long gBuiltinBootArchiveSize; 34 35static TFTP sTFTP; 36 37 38status_t 39platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) 40{ 41 TRACE("platform_add_boot_device\n"); 42 43 // get the boot archive containing kernel and drivers via TFTP 44 status_t error = sTFTP.Init(); 45 if (error == B_OK) { 46 uint8* data; 47 size_t size; 48 // The root path in the DHCP packet from the server might contain the 49 // name of the archive. It would come first, then separated by semicolon 50 // the actual root path. 51 const char* fileName = "haiku-netboot.tgz"; // default 52 char stackFileName[1024]; 53 const char* rootPath = sTFTP.RootPath(); 54 if (rootPath) { 55 if (char* fileNameEnd = strchr(rootPath, ';')) { 56 size_t len = min_c(fileNameEnd - rootPath, 57 (int)sizeof(stackFileName) - 1); 58 memcpy(stackFileName, rootPath, len); 59 stackFileName[len] = '\0'; 60 fileName = stackFileName; 61 } 62 } 63 64 // get the file 65 error = sTFTP.ReceiveFile(fileName, &data, &size); 66 if (error == B_OK) { 67 char name[64]; 68 ip_addr_t serverAddress = sTFTP.ServerIPAddress(); 69 snprintf(name, sizeof(name), "%lu.%lu.%lu.%lu:%s", 70 (serverAddress >> 24), (serverAddress >> 16) & 0xff, 71 (serverAddress >> 8) & 0xff, serverAddress & 0xff, fileName); 72 73 MemoryDisk* disk = new(nothrow) MemoryDisk(data, size, name); 74 if (!disk) { 75 dprintf("platform_add_boot_device(): Out of memory!\n"); 76 platform_free_region(data, size); 77 return B_NO_MEMORY; 78 } 79 80 gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, true); 81 devicesList->Add(disk); 82 return B_OK; 83 } else { 84 dprintf("platform_add_boot_device(): Failed to load file \"%s\" " 85 "via TFTP\n", fileName); 86 } 87 } 88 89 return B_ENTRY_NOT_FOUND; 90 91// // built-in boot archive? 92// if (gBuiltinBootArchiveSize > 0) { 93// MemoryDisk* disk = new(nothrow) MemoryDisk(gBuiltinBootArchive, 94// gBuiltinBootArchiveSize); 95// if (!disk) 96// return B_NO_MEMORY; 97// 98// devicesList->Add(disk); 99// return B_OK; 100// } 101 102// error = net_stack_init(); 103// if (error != B_OK) 104// return error; 105// 106// // init a remote disk, if possible 107// RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk(); 108// if (!remoteDisk) { 109// unsigned ip = NetStack::Default()->GetEthernetInterface()->IPAddress(); 110// panic("PXE boot: can't find remote disk on server %u.%u.%u.%u\n", 111// (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); 112// return B_ENTRY_NOT_FOUND; 113// } 114// 115// devicesList->Add(remoteDisk); 116// return B_OK; 117} 118 119 120status_t 121platform_get_boot_partitions(struct stage2_args *args, Node *device, 122 NodeList *list, NodeList *partitionList) 123{ 124 TRACE("platform_get_boot_partition\n"); 125 NodeIterator iterator = list->GetIterator(); 126 boot::Partition *partition = NULL; 127 while ((partition = (boot::Partition *)iterator.Next()) != NULL) { 128 // ToDo: just take the first partition for now 129 partitionList->Insert(partition); 130 return B_OK; 131 } 132 133 return B_ENTRY_NOT_FOUND; 134} 135 136 137status_t 138platform_add_block_devices(stage2_args *args, NodeList *devicesList) 139{ 140 TRACE("platform_add_block_devices\n"); 141 return B_OK; 142} 143 144 145status_t 146platform_register_boot_device(Node *device) 147{ 148 TRACE("platform_register_boot_device\n"); 149 150 // get the root path -- chop off the file name of the archive we loaded 151 const char* rootPath = sTFTP.RootPath(); 152 if (rootPath) { 153 if (char* fileNameEnd = strchr(rootPath, ';')) 154 rootPath = fileNameEnd + 1; 155 } 156 157 if (gBootVolume.SetInt32(BOOT_METHOD, BOOT_METHOD_NET) != B_OK 158 || gBootVolume.AddInt64("client MAC", 159 sTFTP.MACAddress().ToUInt64()) != B_OK 160 || gBootVolume.AddInt32("client IP", sTFTP.IPAddress()) != B_OK 161 || gBootVolume.AddInt32("server IP", sTFTP.ServerIPAddress()) != B_OK 162 || gBootVolume.AddInt32("server port", sTFTP.ServerPort()) != B_OK 163 || (sTFTP.RootPath() 164 && gBootVolume.AddString("net root path", rootPath) 165 != B_OK)) { 166 return B_NO_MEMORY; 167 } 168 169// RemoteDisk *rd = static_cast<RemoteDisk *>(device); 170// UNDI *undi = static_cast<UNDI *>(NetStack::Default()->GetEthernetInterface()); 171// 172// gKernelArgs.boot_disk.identifier.bus_type = UNKNOWN_BUS; 173// gKernelArgs.boot_disk.identifier.device_type = NETWORK_DEVICE; 174// gKernelArgs.boot_disk.identifier.device.network.client_ip = undi->IPAddress(); 175// gKernelArgs.boot_disk.identifier.device.network.server_ip = rd->ServerIPAddress(); 176// gKernelArgs.boot_disk.identifier.device.network.server_port = rd->ServerPort(); 177// gKernelArgs.boot_disk.partition_offset = 0; 178// gKernelArgs.boot_disk.user_selected = false; 179// gKernelArgs.boot_disk.booted_from_image = false; 180// gKernelArgs.boot_disk.booted_from_network = true; 181// gKernelArgs.boot_disk.cd = false; 182 183 return B_OK; 184} 185 186 187void 188platform_cleanup_devices() 189{ 190 net_stack_cleanup(); 191} 192