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