xref: /haiku/src/system/boot/platform/pxe_ia32/devices.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
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 			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 
118 status_t
119 platform_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 
135 status_t
136 platform_add_block_devices(stage2_args *args, NodeList *devicesList)
137 {
138 	TRACE("platform_add_block_devices\n");
139 	return B_OK;
140 }
141 
142 
143 status_t
144 platform_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