xref: /haiku/src/system/boot/platform/pxe_ia32/devices.cpp (revision 5e7964b0a929555415798dea3373db9ac4611caa)
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 
34 static TFTP sTFTP;
35 
36 
37 status_t
38 platform_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 			gBootVolume.SetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, true);
80 			devicesList->Add(disk);
81 			return B_OK;
82 		} else {
83 			dprintf("platform_add_boot_device(): Failed to load file \"%s\" "
84 				"via TFTP\n", fileName);
85 		}
86 	}
87 
88 	return B_ENTRY_NOT_FOUND;
89 
90 // 	// built-in boot archive?
91 // 	if (gBuiltinBootArchiveSize > 0) {
92 // 		MemoryDisk* disk = new(nothrow) MemoryDisk(gBuiltinBootArchive,
93 // 			gBuiltinBootArchiveSize);
94 // 		if (!disk)
95 // 			return B_NO_MEMORY;
96 //
97 // 		devicesList->Add(disk);
98 // 		return B_OK;
99 // 	}
100 
101 // 	error = net_stack_init();
102 // 	if (error != B_OK)
103 // 		return error;
104 //
105 // 	// init a remote disk, if possible
106 // 	RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk();
107 // 	if (!remoteDisk) {
108 // 		unsigned ip = NetStack::Default()->GetEthernetInterface()->IPAddress();
109 // 		panic("PXE boot: can't find remote disk on server %u.%u.%u.%u\n",
110 // 			(ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
111 // 		return B_ENTRY_NOT_FOUND;
112 // 	}
113 //
114 // 	devicesList->Add(remoteDisk);
115 // 	return B_OK;
116 }
117 
118 
119 status_t
120 platform_get_boot_partition(struct stage2_args *args, Node *device,
121 	NodeList *list, boot::Partition **_partition)
122 {
123 	TRACE("platform_get_boot_partition\n");
124 	NodeIterator iterator = list->GetIterator();
125 	boot::Partition *partition = NULL;
126 	while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
127 		// ToDo: just take the first partition for now
128 		*_partition = partition;
129 		return B_OK;
130 	}
131 
132 	return B_ENTRY_NOT_FOUND;
133 }
134 
135 
136 status_t
137 platform_add_block_devices(stage2_args *args, NodeList *devicesList)
138 {
139 	TRACE("platform_add_block_devices\n");
140 	return B_OK;
141 }
142 
143 
144 status_t
145 platform_register_boot_device(Node *device)
146 {
147 	TRACE("platform_register_boot_device\n");
148 
149 	// get the root path -- chop off the file name of the archive we loaded
150 	const char* rootPath = sTFTP.RootPath();
151 	if (rootPath) {
152 		if (char* fileNameEnd = strchr(rootPath, ';'))
153 			rootPath = fileNameEnd + 1;
154 	}
155 
156 	if (gBootVolume.SetInt32(BOOT_METHOD, BOOT_METHOD_NET) != B_OK
157 		|| gBootVolume.AddInt64("client MAC",
158 			sTFTP.MACAddress().ToUInt64()) != B_OK
159 		|| gBootVolume.AddInt32("client IP", sTFTP.IPAddress()) != B_OK
160 		|| gBootVolume.AddInt32("server IP", sTFTP.ServerIPAddress()) != B_OK
161 		|| gBootVolume.AddInt32("server port", sTFTP.ServerPort()) != B_OK
162 		|| (sTFTP.RootPath()
163 			&& gBootVolume.AddString("net root path", rootPath)
164 				!= B_OK)) {
165 		return B_NO_MEMORY;
166 	}
167 
168 // 	RemoteDisk *rd = static_cast<RemoteDisk *>(device);
169 // 	UNDI *undi = static_cast<UNDI *>(NetStack::Default()->GetEthernetInterface());
170 //
171 // 	gKernelArgs.boot_disk.identifier.bus_type = UNKNOWN_BUS;
172 // 	gKernelArgs.boot_disk.identifier.device_type = NETWORK_DEVICE;
173 // 	gKernelArgs.boot_disk.identifier.device.network.client_ip = undi->IPAddress();
174 // 	gKernelArgs.boot_disk.identifier.device.network.server_ip = rd->ServerIPAddress();
175 // 	gKernelArgs.boot_disk.identifier.device.network.server_port = rd->ServerPort();
176 // 	gKernelArgs.boot_disk.partition_offset = 0;
177 // 	gKernelArgs.boot_disk.user_selected = false;
178 // 	gKernelArgs.boot_disk.booted_from_image = false;
179 // 	gKernelArgs.boot_disk.booted_from_network = true;
180 // 	gKernelArgs.boot_disk.cd = false;
181 
182 	return B_OK;
183 }
184