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