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