xref: /haiku/src/system/boot/platform/openfirmware/devices.cpp (revision 294711f98c107cf2d9d05b7fc34cd863e87bd358)
1 /*
2  * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2010, Andreas Färber <andreas.faerber@web.de>
4  * All rights reserved. Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <string.h>
9 
10 #include <boot/platform.h>
11 #include <boot/vfs.h>
12 #include <boot/stdio.h>
13 #include <boot/stage2.h>
14 #include <boot/net/IP.h>
15 #include <boot/net/iSCSITarget.h>
16 #include <boot/net/NetStack.h>
17 #include <boot/net/RemoteDisk.h>
18 #include <platform/openfirmware/devices.h>
19 #include <platform/openfirmware/openfirmware.h>
20 #include <util/kernel_cpp.h>
21 
22 #include "Handle.h"
23 #include "machine.h"
24 
25 
26 #define ENABLE_ISCSI
27 
28 
29 char sBootPath[192];
30 
31 
32 status_t
33 platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
34 {
35 	// print out the boot path (to be removed later?)
36 
37 	int length = of_getprop(gChosen, "bootpath", sBootPath, sizeof(sBootPath));
38 	if (length <= 1)
39 		return B_ENTRY_NOT_FOUND;
40 	printf("boot path = \"%s\"\n", sBootPath);
41 
42 	int node = of_finddevice(sBootPath);
43 	if (node != OF_FAILED) {
44 		char type[16];
45 		of_getprop(node, "device_type", type, sizeof(type));
46 		printf("boot type = %s\n", type);
47 
48 		// If the boot device is a network device, we try to find a
49 		// "remote disk" at this point.
50 		if (strcmp(type, "network") == 0) {
51 			// init the net stack
52 			status_t error = net_stack_init();
53 			if (error != B_OK)
54 				return error;
55 
56 			ip_addr_t bootAddress = 0;
57 			char* bootArgs = strrchr(sBootPath, ':');
58 			if (bootArgs != NULL) {
59 				bootArgs++;
60 				char* comma = strchr(bootArgs, ',');
61 				if (comma != NULL && comma - bootArgs > 0) {
62 					comma[0] = '\0';
63 					bootAddress = ip_parse_address(bootArgs);
64 					comma[0] = ',';
65 				}
66 			}
67 			if (bootAddress == 0) {
68 				int package = of_finddevice("/options");
69 				char defaultServerIP[16];
70 				int bytesRead = of_getprop(package, "default-server-ip",
71 					defaultServerIP, sizeof(defaultServerIP) - 1);
72 				if (bytesRead != OF_FAILED && bytesRead > 1) {
73 					defaultServerIP[bytesRead] = '\0';
74 					bootAddress = ip_parse_address(defaultServerIP);
75 				}
76 			}
77 
78 			// init a remote disk, if possible
79 			RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk();
80 			if (remoteDisk != NULL) {
81 				devicesList->Add(remoteDisk);
82 				return B_OK;
83 			}
84 
85 #ifdef ENABLE_ISCSI
86 			if (bootAddress != 0) {
87 				if (iSCSITarget::DiscoverTargets(bootAddress, ISCSI_PORT,
88 						devicesList))
89 					return B_OK;
90 			}
91 #endif
92 
93 			return B_ENTRY_NOT_FOUND;
94 		}
95 
96 		if (strcmp("block", type) != 0) {
97 			printf("boot device is not a block device!\n");
98 			return B_ENTRY_NOT_FOUND;
99 		}
100 	} else
101 		printf("could not open boot path.\n");
102 
103 /*	char name[256];
104 	strcpy(name, sBootPath);
105 	strcat(name, ":kernel_ppc");
106 	int kernel = of_open(name);
107 	if (kernel == OF_FAILED) {
108 		puts("open kernel failed");
109 	} else
110 		puts("open kernel succeeded");
111 */
112 	int handle = of_open(sBootPath);
113 	if (handle == OF_FAILED) {
114 		puts("\t\t(open failed)");
115 		return B_ERROR;
116 	}
117 
118 	Handle *device = new(nothrow) Handle(handle);
119 	if (device == NULL)
120 		return B_NO_MEMORY;
121 
122 	devicesList->Add(device);
123 	return B_OK;
124 }
125 
126 
127 status_t
128 platform_get_boot_partition(struct stage2_args *args, Node *device,
129 	NodeList *list, boot::Partition **_partition)
130 {
131 	NodeIterator iterator = list->GetIterator();
132 	boot::Partition *partition = NULL;
133 	while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
134 		// ToDo: just take the first partition for now
135 		*_partition = partition;
136 		return B_OK;
137 	}
138 
139 	return B_ENTRY_NOT_FOUND;
140 }
141 
142 
143 #define DUMPED_BLOCK_SIZE 16
144 
145 void
146 dumpBlock(const char *buffer, int size, const char *prefix)
147 {
148 	int i;
149 
150 	for (i = 0; i < size;) {
151 		int start = i;
152 
153 		printf(prefix);
154 		for (; i < start+DUMPED_BLOCK_SIZE; i++) {
155 			if (!(i % 4))
156 				printf(" ");
157 
158 			if (i >= size)
159 				printf("  ");
160 			else
161 				printf("%02x", *(unsigned char *)(buffer + i));
162 		}
163 		printf("  ");
164 
165 		for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) {
166 			if (i < size) {
167 				char c = buffer[i];
168 
169 				if (c < 30)
170 					printf(".");
171 				else
172 					printf("%c", c);
173 			} else
174 				break;
175 		}
176 		printf("\n");
177 	}
178 }
179 
180 
181 status_t
182 platform_add_block_devices(stage2_args *args, NodeList *devicesList)
183 {
184 	// add all block devices to the list of possible boot devices
185 
186 	int cookie = 0;
187 	char path[256];
188 	status_t status;
189 	while ((status = of_get_next_device(&cookie, 0, "block", path,
190 			sizeof(path))) == B_OK) {
191 		if (!strcmp(path, sBootPath)) {
192 			// don't add the boot device twice
193 			continue;
194 		}
195 
196 		// Adjust the arguments passed to the open command so that
197 		// the disk-label package is by-passed - unfortunately,
198 		// this is implementation specific (and I found no docs
199 		// for the Apple OF disk-label usage, of course)
200 
201 		// SUN's OpenBoot:
202 		//strcpy(path + strlen(path), ":nolabel");
203 		// Apple:
204 		if (gMachine & MACHINE_MAC)
205 			strcpy(path + strlen(path), ":0");
206 
207 		printf("\t%s\n", path);
208 
209 		int handle = of_open(path);
210 		if (handle == OF_FAILED) {
211 			puts("\t\t(failed)");
212 			continue;
213 		}
214 
215 		Handle *device = new(nothrow) Handle(handle);
216 		printf("\t\t(could open device, handle = %p, node = %p)\n",
217 			(void *)handle, device);
218 
219 		devicesList->Add(device);
220 	}
221 	printf("\t(loop ended with %ld)\n", status);
222 
223 	return B_OK;
224 }
225 
226 
227 status_t
228 platform_register_boot_device(Node *device)
229 {
230 	disk_identifier disk;
231 
232 	disk.bus_type = UNKNOWN_BUS;
233 	disk.device_type = UNKNOWN_DEVICE;
234 	disk.device.unknown.size = device->Size();
235 
236 	gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, &disk,
237 		sizeof(disk_identifier));
238 
239 	return B_OK;
240 }
241 
242