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