* Copyright 2003-2006, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2006, Marcus Overhagen, marcus@overhagen.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "bios.h"
#include "pxe_undi.h"
#include "network.h"
#include <KernelExport.h>
#include <boot/partitions.h>
#include <boot/platform.h>
#include <boot/vfs.h>
#include <boot/stdio.h>
#include <boot/stage2.h>
#include <boot/net/NetStack.h>
#include <boot/net/RemoteDisk.h>
#include <util/kernel_cpp.h>
#include <util/KMessage.h>
#include <string.h>
#define TRACE_DEVICES
#ifdef TRACE_DEVICES
# define TRACE(x...) dprintf(x)
#else
# define TRACE(x...)
#endif
static TFTP sTFTP;
status_t
platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
{
TRACE("platform_add_boot_device\n");
status_t error = sTFTP.Init();
if (error == B_OK) {
uint8* data;
size_t size;
const char* fileName = "haiku-netboot.tgz";
char stackFileName[1024];
const char* rootPath = sTFTP.RootPath();
if (rootPath) {
if (char* fileNameEnd = strchr(rootPath, ';')) {
size_t len = min_c(fileNameEnd - rootPath,
(int)sizeof(stackFileName) - 1);
memcpy(stackFileName, rootPath, len);
stackFileName[len] = '\0';
fileName = stackFileName;
}
}
error = sTFTP.ReceiveFile(fileName, &data, &size);
if (error == B_OK) {
char name[64];
ip_addr_t serverAddress = sTFTP.ServerIPAddress();
snprintf(name, sizeof(name), "%u.%u.%u.%u:%s",
(serverAddress >> 24), (serverAddress >> 16) & 0xff,
(serverAddress >> 8) & 0xff, serverAddress & 0xff, fileName);
MemoryDisk* disk = new(nothrow) MemoryDisk(data, size, name);
if (!disk) {
dprintf("platform_add_boot_device(): Out of memory!\n");
platform_free_region(data, size);
return B_NO_MEMORY;
}
gBootParams.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, true);
gBootParams.SetInt32(BOOT_METHOD, BOOT_METHOD_NET);
devicesList->Add(disk);
return B_OK;
} else {
dprintf("platform_add_boot_device(): Failed to load file \"%s\" "
"via TFTP\n", fileName);
}
}
return B_ENTRY_NOT_FOUND;
}
status_t
platform_get_boot_partitions(struct stage2_args *args, Node *device,
NodeList *list, NodeList *partitionList)
{
TRACE("platform_get_boot_partition\n");
NodeIterator iterator = list->GetIterator();
boot::Partition *partition = NULL;
while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
partitionList->Insert(partition);
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
status_t
platform_add_block_devices(stage2_args *args, NodeList *devicesList)
{
TRACE("platform_add_block_devices\n");
return B_OK;
}
status_t
platform_register_boot_device(Node *device)
{
TRACE("platform_register_boot_device\n");
const char* rootPath = sTFTP.RootPath();
if (rootPath) {
if (char* fileNameEnd = strchr(rootPath, ';'))
rootPath = fileNameEnd + 1;
}
if (gBootParams.SetInt32(BOOT_METHOD, BOOT_METHOD_NET) != B_OK
|| gBootParams.AddInt64("client MAC",
sTFTP.MACAddress().ToUInt64()) != B_OK
|| gBootParams.AddInt32("client IP", sTFTP.IPAddress()) != B_OK
|| gBootParams.AddInt32("server IP", sTFTP.ServerIPAddress()) != B_OK
|| gBootParams.AddInt32("server port", sTFTP.ServerPort()) != B_OK
|| (sTFTP.RootPath()
&& gBootParams.AddString("net root path", rootPath)
!= B_OK)) {
return B_NO_MEMORY;
}
return B_OK;
}
void
platform_cleanup_devices()
{
net_stack_cleanup();
}