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
29char sBootPath[192];
30
31
32status_t
33platform_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
127status_t
128platform_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
145void
146dumpBlock(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
181status_t
182platform_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
227status_t
228platform_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