propagate required settings for the remote disk from boot loader to kernel (client-ip, server-ip, server-port)
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19780 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
93b2b9ce66
commit
43792b9eed
@ -23,6 +23,7 @@ enum device_types {
|
||||
USB_DEVICE,
|
||||
FIREWIRE_DEVICE,
|
||||
FIBRE_DEVICE,
|
||||
NETWORK_DEVICE,
|
||||
};
|
||||
|
||||
#define NUM_DISK_CHECK_SUMS 5
|
||||
@ -61,6 +62,11 @@ typedef struct disk_identifier {
|
||||
struct {
|
||||
uint64 wwd;
|
||||
} fibre;
|
||||
struct {
|
||||
uint32 client_ip;
|
||||
uint32 server_ip;
|
||||
uint16 server_port;
|
||||
} network;
|
||||
struct {
|
||||
off_t size;
|
||||
struct {
|
||||
|
@ -46,6 +46,7 @@ typedef struct kernel_args {
|
||||
off_t partition_offset;
|
||||
bool user_selected;
|
||||
bool booted_from_image;
|
||||
bool booted_from_network;
|
||||
bool cd;
|
||||
} boot_disk;
|
||||
|
||||
|
@ -28,6 +28,9 @@ public:
|
||||
virtual status_t GetName(char *nameBuffer, size_t bufferSize) const;
|
||||
virtual off_t Size() const;
|
||||
|
||||
ip_addr_t ServerIPAddress() const;
|
||||
uint16 ServerPort() const;
|
||||
|
||||
static RemoteDisk *FindAnyRemoteDisk();
|
||||
|
||||
private:
|
||||
|
@ -179,6 +179,18 @@ RemoteDisk::Size() const
|
||||
return fImageSize;
|
||||
}
|
||||
|
||||
ip_addr_t
|
||||
RemoteDisk::ServerIPAddress() const
|
||||
{
|
||||
return fServerAddress;
|
||||
}
|
||||
|
||||
uint16
|
||||
RemoteDisk::ServerPort() const
|
||||
{
|
||||
return fServerPort;
|
||||
}
|
||||
|
||||
// FindAnyRemoteDisk
|
||||
RemoteDisk *
|
||||
RemoteDisk::FindAnyRemoteDisk()
|
||||
|
@ -757,6 +757,7 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
|
||||
|
||||
TRACE(("boot drive size: %Ld bytes\n", drive->Size()));
|
||||
gKernelArgs.boot_disk.booted_from_image = gBootedFromImage;
|
||||
gKernelArgs.boot_disk.booted_from_network = false;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "bios.h"
|
||||
#include "pxe_undi.h"
|
||||
#include "network.h"
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <boot/platform.h>
|
||||
@ -37,8 +38,12 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
|
||||
|
||||
// init a remote disk, if possible
|
||||
RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk();
|
||||
if (!remoteDisk)
|
||||
if (!remoteDisk) {
|
||||
unsigned ip = NetStack::Default()->GetEthernetInterface()->IPAddress();
|
||||
panic("PXE boot: can't find remote disk on server %u.%u.%u.%u\n",
|
||||
(ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
devicesList->Add(remoteDisk);
|
||||
return B_OK;
|
||||
@ -74,11 +79,23 @@ status_t
|
||||
platform_register_boot_device(Node *device)
|
||||
{
|
||||
TRACE("platform_register_boot_device\n");
|
||||
disk_identifier &disk = gKernelArgs.boot_disk.identifier;
|
||||
|
||||
disk.bus_type = UNKNOWN_BUS;
|
||||
disk.device_type = UNKNOWN_DEVICE;
|
||||
disk.device.unknown.size = device->Size();
|
||||
gKernelArgs.platform_args.boot_drive_number = 0xffff;
|
||||
gKernelArgs.platform_args.drives = NULL;
|
||||
|
||||
RemoteDisk *rd = static_cast<RemoteDisk *>(device);
|
||||
UNDI *undi = static_cast<UNDI *>(NetStack::Default()->GetEthernetInterface());
|
||||
|
||||
gKernelArgs.boot_disk.identifier.bus_type = UNKNOWN_BUS;
|
||||
gKernelArgs.boot_disk.identifier.device_type = NETWORK_DEVICE;
|
||||
gKernelArgs.boot_disk.identifier.device.network.client_ip = undi->IPAddress();
|
||||
gKernelArgs.boot_disk.identifier.device.network.server_ip = rd->ServerIPAddress();
|
||||
gKernelArgs.boot_disk.identifier.device.network.server_port = rd->ServerPort();
|
||||
gKernelArgs.boot_disk.partition_offset = 0;
|
||||
gKernelArgs.boot_disk.user_selected = false;
|
||||
gKernelArgs.boot_disk.booted_from_image = false;
|
||||
gKernelArgs.boot_disk.booted_from_network = true;
|
||||
gKernelArgs.boot_disk.cd = false;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -9,12 +9,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <OS.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <boot/net/Ethernet.h>
|
||||
#include <boot/net/NetStack.h>
|
||||
|
||||
#include "network.h"
|
||||
#include "pxe_undi.h"
|
||||
|
||||
//#define TRACE_NETWORK
|
||||
@ -52,29 +49,6 @@ hex_dump(const void *_data, int length)
|
||||
#endif // !TRACE_NETWORK
|
||||
|
||||
|
||||
class UNDI : public EthernetInterface
|
||||
{
|
||||
public:
|
||||
UNDI();
|
||||
virtual ~UNDI();
|
||||
|
||||
status_t Init();
|
||||
|
||||
virtual mac_addr_t MACAddress() const;
|
||||
|
||||
virtual void * AllocateSendReceiveBuffer(size_t size);
|
||||
virtual void FreeSendReceiveBuffer(void *buffer);
|
||||
|
||||
virtual ssize_t Send(const void *buffer, size_t size);
|
||||
virtual ssize_t Receive(void *buffer, size_t size);
|
||||
|
||||
private:
|
||||
mac_addr_t fMACAddress;
|
||||
bool fRxFinished;
|
||||
PXE_STRUCT * fPxeData;
|
||||
};
|
||||
|
||||
|
||||
UNDI::UNDI()
|
||||
: fMACAddress()
|
||||
, fRxFinished(true)
|
||||
@ -123,7 +97,9 @@ UNDI::Init()
|
||||
ip_addr_t ipClient = ntohl(*(ip_addr_t *)(buf + 16));
|
||||
ip_addr_t ipServer = ntohl(*(ip_addr_t *)(buf + 20));
|
||||
|
||||
dprintf("client-ip: %08x, server-ip: %08x\n", (int)ipClient, (int)ipServer);
|
||||
dprintf("client-ip: %lu.%lu.%lu.%lu, server-ip: %lu.%lu.%lu.%lu\n",
|
||||
(ipClient >> 24) & 0xff, (ipClient >> 16) & 0xff, (ipClient >> 8) & 0xff, ipClient & 0xff,
|
||||
(ipServer >> 24) & 0xff, (ipServer >> 16) & 0xff, (ipServer >> 8) & 0xff, ipServer & 0xff);
|
||||
|
||||
SetIPAddress(ipClient);
|
||||
|
||||
|
@ -1,56 +1,16 @@
|
||||
#ifndef _PXE_NETWORK_H
|
||||
#define _PXE_NETWORK_H
|
||||
/*
|
||||
* Copyright 2006, Marcus Overhagen <marcus@overhagen.de. All rights reserved.
|
||||
* Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <OS.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <boot/net/Ethernet.h>
|
||||
#include <boot/net/NetStack.h>
|
||||
|
||||
#include "pxe_undi.h"
|
||||
|
||||
//#define TRACE_NETWORK
|
||||
#ifdef TRACE_NETWORK
|
||||
# define TRACE(x...) dprintf(x)
|
||||
#else
|
||||
# define TRACE(x...)
|
||||
#endif
|
||||
|
||||
#ifdef TRACE_NETWORK
|
||||
|
||||
static void
|
||||
hex_dump(const void *_data, int length)
|
||||
{
|
||||
uint8 *data = (uint8*)_data;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (i % 4 == 0) {
|
||||
if (i % 32 == 0) {
|
||||
if (i != 0)
|
||||
TRACE("\n");
|
||||
TRACE("%03x: ", i);
|
||||
} else
|
||||
TRACE(" ");
|
||||
}
|
||||
|
||||
TRACE("%02x", data[i]);
|
||||
}
|
||||
TRACE("\n");
|
||||
}
|
||||
|
||||
#else // !TRACE_NETWORK
|
||||
|
||||
#define hex_dump(data, length)
|
||||
|
||||
#endif // !TRACE_NETWORK
|
||||
|
||||
struct PXE_STRUCT;
|
||||
|
||||
class UNDI : public EthernetInterface
|
||||
{
|
||||
@ -60,6 +20,7 @@ public:
|
||||
|
||||
status_t Init();
|
||||
|
||||
ip_addr_t ServerIPAddress() const;
|
||||
virtual mac_addr_t MACAddress() const;
|
||||
|
||||
virtual void * AllocateSendReceiveBuffer(size_t size);
|
||||
@ -74,274 +35,4 @@ private:
|
||||
PXE_STRUCT * fPxeData;
|
||||
};
|
||||
|
||||
|
||||
UNDI::UNDI()
|
||||
: fMACAddress()
|
||||
, fRxFinished(true)
|
||||
, fPxeData(NULL)
|
||||
{
|
||||
TRACE("UNDI::UNDI\n");
|
||||
|
||||
fPxeData = pxe_undi_find_data();
|
||||
if (!fPxeData)
|
||||
panic("can't find !PXE structure");
|
||||
|
||||
dprintf("PXE API entrypoint at %04x:%04x\n", fPxeData->EntryPointSP.seg, fPxeData->EntryPointSP.ofs);
|
||||
}
|
||||
|
||||
|
||||
UNDI::~UNDI()
|
||||
{
|
||||
TRACE("UNDI::~UNDI\n");
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
UNDI::Init()
|
||||
{
|
||||
TRACE("UNDI::Init\n");
|
||||
|
||||
PXENV_GET_CACHED_INFO cached_info;
|
||||
PXENV_UNDI_GET_INFORMATION get_info;
|
||||
PXENV_UNDI_GET_STATE get_state;
|
||||
PXENV_UNDI_OPEN undi_open;
|
||||
uint16 res;
|
||||
|
||||
cached_info.PacketType = PXENV_PACKET_TYPE_CACHED_REPLY;
|
||||
cached_info.BufferSize = 0;
|
||||
cached_info.BufferLimit = 0;
|
||||
cached_info.Buffer.seg = 0;
|
||||
cached_info.Buffer.ofs = 0;
|
||||
res = call_pxe_bios(fPxeData, GET_CACHED_INFO, &cached_info);
|
||||
if (res != 0 || cached_info.Status != 0) {
|
||||
char s[100];
|
||||
snprintf(s, sizeof(s), "Can't determine IP address! PXENV_GET_CACHED_INFO res %x, status %x\n", res, cached_info.Status);
|
||||
panic(s);
|
||||
}
|
||||
|
||||
char *buf = (char *)(cached_info.Buffer.seg * 16 + cached_info.Buffer.ofs);
|
||||
ip_addr_t ipClient = ntohl(*(ip_addr_t *)(buf + 16));
|
||||
ip_addr_t ipServer = ntohl(*(ip_addr_t *)(buf + 20));
|
||||
|
||||
dprintf("client-ip: %08x, server-ip: %08x\n", (int)ipClient, (int)ipServer);
|
||||
|
||||
SetIPAddress(ipClient);
|
||||
|
||||
undi_open.OpenFlag = 0;
|
||||
undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS;
|
||||
undi_open.R_Mcast_Buf.MCastAddrCount = 0;
|
||||
|
||||
res = call_pxe_bios(fPxeData, UNDI_OPEN, &undi_open);
|
||||
if (res != 0 || undi_open.Status != 0) {
|
||||
dprintf("PXENV_UNDI_OPEN failed, res %x, status %x, ignoring\n", res, undi_open.Status);
|
||||
}
|
||||
|
||||
res = call_pxe_bios(fPxeData, UNDI_GET_STATE, &get_state);
|
||||
if (res != 0 || get_state.Status != 0) {
|
||||
dprintf("PXENV_UNDI_GET_STATE failed, res %x, status %x, ignoring\n", res, get_state.Status);
|
||||
} else {
|
||||
switch (get_state.UNDIstate) {
|
||||
case PXE_UNDI_GET_STATE_STARTED:
|
||||
TRACE("PXE_UNDI_GET_STATE_STARTED\n");
|
||||
break;
|
||||
case PXE_UNDI_GET_STATE_INITIALIZED:
|
||||
TRACE("PXE_UNDI_GET_STATE_INITIALIZED\n");
|
||||
break;
|
||||
case PXE_UNDI_GET_STATE_OPENED:
|
||||
TRACE("PXE_UNDI_GET_STATE_OPENED\n");
|
||||
break;
|
||||
default:
|
||||
TRACE("unknown undi state 0x%02x\n", get_state.UNDIstate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res = call_pxe_bios(fPxeData, UNDI_GET_INFORMATION, &get_info);
|
||||
if (res != 0 || get_info.Status != 0) {
|
||||
dprintf("PXENV_UNDI_GET_INFORMATION failed, res %x, status %x\n", res, get_info.Status);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("Status = %x\n", get_info.Status);
|
||||
TRACE("BaseIo = %x\n", get_info.BaseIo);
|
||||
TRACE("IntNumber = %x\n", get_info.IntNumber);
|
||||
TRACE("MaxTranUnit = %x\n", get_info.MaxTranUnit);
|
||||
TRACE("HwType = %x\n", get_info.HwType);
|
||||
TRACE("HwAddrLen = %x\n", get_info.HwAddrLen);
|
||||
TRACE("RxBufCt = %x\n", get_info.RxBufCt);
|
||||
TRACE("TxBufCt = %x\n", get_info.TxBufCt);
|
||||
|
||||
fMACAddress = get_info.CurrentNodeAddress;
|
||||
|
||||
TRACE("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", fMACAddress[0], fMACAddress[1], fMACAddress[2], fMACAddress[3], fMACAddress[4], fMACAddress[5]);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
mac_addr_t
|
||||
UNDI::MACAddress() const
|
||||
{
|
||||
return fMACAddress;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
UNDI::AllocateSendReceiveBuffer(size_t size)
|
||||
{
|
||||
TRACE("UNDI::AllocateSendReceiveBuffer, size %ld\n", size);
|
||||
if (size > 0x3000)
|
||||
return NULL;
|
||||
|
||||
return (void *)0x500;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UNDI::FreeSendReceiveBuffer(void *buffer)
|
||||
{
|
||||
TRACE("UNDI::FreeSendReceiveBuffer\n");
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
UNDI::Send(const void *buffer, size_t size)
|
||||
{
|
||||
TRACE("UNDI::Send, buffer %p, size %ld\n", buffer, size);
|
||||
|
||||
// hex_dump(buffer, size);
|
||||
|
||||
PXENV_UNDI_TRANSMIT undi_tx;
|
||||
PXENV_UNDI_TBD undi_tbd;
|
||||
|
||||
undi_tx.Protocol = P_UNKNOWN;
|
||||
undi_tx.XmitFlag = XMT_DESTADDR;
|
||||
undi_tx.DestAddr.seg = SEG((char *)buffer + 16);
|
||||
undi_tx.DestAddr.ofs = OFS((char *)buffer + 16);
|
||||
undi_tx.TBD.seg = SEG(&undi_tbd);
|
||||
undi_tx.TBD.ofs = OFS(&undi_tbd);
|
||||
|
||||
undi_tbd.ImmedLength = size;
|
||||
undi_tbd.Xmit.seg = SEG(buffer);
|
||||
undi_tbd.Xmit.ofs = OFS(buffer);
|
||||
undi_tbd.DataBlkCount = 0;
|
||||
|
||||
uint16 res = call_pxe_bios(fPxeData, UNDI_TRANSMIT, &undi_tx);
|
||||
if (res != 0 || undi_tx.Status != 0) {
|
||||
dprintf("UNDI_TRANSMIT failed, res %x, status %x\n", res, undi_tx.Status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE("UNDI_TRANSMIT success\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
UNDI::Receive(void *buffer, size_t size)
|
||||
{
|
||||
//TRACE("UNDI::Receive, buffer %p, size %ld\n", buffer, size);
|
||||
|
||||
PXENV_UNDI_ISR undi_isr;
|
||||
uint16 res;
|
||||
|
||||
if (!fRxFinished) {
|
||||
TRACE("continue receive...\n");
|
||||
|
||||
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
|
||||
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
|
||||
if (res != 0 || undi_isr.Status != 0) {
|
||||
dprintf("PXENV_UNDI_ISR_IN_GET_NEXT failed, res %x, status %x\n", res, undi_isr.Status);
|
||||
fRxFinished = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
|
||||
|
||||
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
|
||||
if (res != 0 || undi_isr.Status != 0) {
|
||||
dprintf("PXENV_UNDI_ISR_IN_START failed, res %x, status %x\n", res, undi_isr.Status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS) {
|
||||
// TRACE("not ours\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// send EOI to pic ?
|
||||
|
||||
// TRACE("PXENV_UNDI_ISR_OUT_OURS\n");
|
||||
|
||||
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
|
||||
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
|
||||
if (res != 0 || undi_isr.Status != 0) {
|
||||
dprintf("PXENV_UNDI_ISR_IN_PROCESS failed, res %x, status %x\n", res, undi_isr.Status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (undi_isr.FuncFlag) {
|
||||
case PXENV_UNDI_ISR_OUT_TRANSMIT:
|
||||
TRACE("PXENV_UNDI_ISR_OUT_TRANSMIT\n");
|
||||
fRxFinished = false;
|
||||
return 0;
|
||||
|
||||
case PXENV_UNDI_ISR_OUT_RECEIVE:
|
||||
TRACE("PXENV_UNDI_ISR_OUT_RECEIVE\n");
|
||||
// TRACE("BufferLength %d\n", undi_isr.BufferLength);
|
||||
// TRACE("FrameLength %d\n", undi_isr.FrameLength);
|
||||
// TRACE("FrameHeaderLength %d\n", undi_isr.FrameHeaderLength);
|
||||
if (undi_isr.FrameLength > undi_isr.BufferLength)
|
||||
panic("UNDI::Receive: multi buffer frames not supported");
|
||||
if (size > undi_isr.BufferLength)
|
||||
size = undi_isr.BufferLength;
|
||||
memcpy(buffer, (const void *)(undi_isr.Frame.seg * 16 + undi_isr.Frame.ofs), size);
|
||||
// hex_dump(buffer, size);
|
||||
fRxFinished = false;
|
||||
return size;
|
||||
|
||||
case PXENV_UNDI_ISR_OUT_BUSY:
|
||||
TRACE("PXENV_UNDI_ISR_OUT_BUSY\n");
|
||||
fRxFinished = true;
|
||||
return -1;
|
||||
|
||||
case PXENV_UNDI_ISR_OUT_DONE:
|
||||
TRACE("PXENV_UNDI_ISR_OUT_DONE\n");
|
||||
fRxFinished = true;
|
||||
return -1;
|
||||
|
||||
default:
|
||||
TRACE("default!!!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
platform_net_stack_init()
|
||||
{
|
||||
TRACE("platform_net_stack_init\n");
|
||||
|
||||
UNDI *interface = new(nothrow) UNDI;
|
||||
if (!interface)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = interface->Init();
|
||||
if (error != B_OK) {
|
||||
TRACE("platform_net_stack_init: interface init failed\n");
|
||||
delete interface;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = NetStack::Default()->AddEthernetInterface(interface);
|
||||
if (error != B_OK) {
|
||||
delete interface;
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
|
@ -184,6 +184,7 @@ is_boot_device(kernel_args *args, KDiskDevice *device, bool strict)
|
||||
case USB_DEVICE:
|
||||
case FIREWIRE_DEVICE:
|
||||
case FIBRE_DEVICE:
|
||||
case NETWORK_DEVICE:
|
||||
// TODO: implement me!
|
||||
break;
|
||||
}
|
||||
@ -211,6 +212,12 @@ get_boot_partitions(kernel_args *args, PartitionStack &partitions)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (args->boot_disk.booted_from_network) {
|
||||
panic("get_boot_partitions: boot from network, server %08lx, client %08lx\n",
|
||||
args->boot_disk.identifier.device.network.server_ip,
|
||||
args->boot_disk.identifier.device.network.client_ip);
|
||||
}
|
||||
|
||||
struct BootPartitionVisitor : KPartitionVisitor {
|
||||
BootPartitionVisitor(kernel_args &args, PartitionStack &stack)
|
||||
: fArgs(args), fPartitions(stack) {}
|
||||
|
Loading…
Reference in New Issue
Block a user