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/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	intptr_t 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				intptr_t 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 native remote disk, if possible
79			RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk();
80			if (remoteDisk != NULL) {
81				devicesList->Add(remoteDisk);
82				return B_OK;
83			}
84
85			return B_ENTRY_NOT_FOUND;
86		}
87
88		if (strcmp("block", type) != 0) {
89			printf("boot device is not a block device!\n");
90			return B_ENTRY_NOT_FOUND;
91		}
92	} else
93		printf("could not open boot path.\n");
94
95/*	char name[256];
96	strcpy(name, sBootPath);
97	strcat(name, ":kernel_ppc");
98	int kernel = of_open(name);
99	if (kernel == OF_FAILED) {
100		puts("open kernel failed");
101	} else
102		puts("open kernel succeeded");
103*/
104	int handle = of_open(sBootPath);
105	if (handle == OF_FAILED) {
106		puts("\t\t(open failed)");
107		return B_ERROR;
108	}
109
110	Handle *device = new(nothrow) Handle(handle);
111	if (device == NULL)
112		return B_NO_MEMORY;
113
114	devicesList->Add(device);
115	return B_OK;
116}
117
118
119status_t
120platform_get_boot_partitions(struct stage2_args *args, Node *device,
121	NodeList *list, NodeList *partitionList)
122{
123	NodeIterator iterator = list->GetIterator();
124	boot::Partition *partition = NULL;
125	while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
126		// ToDo: just take the first partition for now
127		partitionList->Insert(partition);
128		return B_OK;
129	}
130
131	return B_ENTRY_NOT_FOUND;
132}
133
134
135void
136platform_cleanup_devices()
137{
138	net_stack_cleanup();
139}
140
141
142#define DUMPED_BLOCK_SIZE 16
143
144void
145dumpBlock(const char *buffer, int size, const char *prefix)
146{
147	int i;
148
149	for (i = 0; i < size;) {
150		int start = i;
151
152		printf(prefix);
153		for (; i < start+DUMPED_BLOCK_SIZE; i++) {
154			if (!(i % 4))
155				printf(" ");
156
157			if (i >= size)
158				printf("  ");
159			else
160				printf("%02x", *(unsigned char *)(buffer + i));
161		}
162		printf("  ");
163
164		for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) {
165			if (i < size) {
166				char c = buffer[i];
167
168				if (c < 30)
169					printf(".");
170				else
171					printf("%c", c);
172			} else
173				break;
174		}
175		printf("\n");
176	}
177}
178
179
180status_t
181platform_add_block_devices(stage2_args *args, NodeList *devicesList)
182{
183	// add all block devices to the list of possible boot devices
184
185	intptr_t cookie = 0;
186	char path[256];
187	status_t status;
188	while ((status = of_get_next_device(&cookie, 0, "block", path,
189			sizeof(path))) == B_OK) {
190		if (!strcmp(path, sBootPath)) {
191			// don't add the boot device twice
192			continue;
193		}
194
195		// Adjust the arguments passed to the open command so that
196		// the disk-label package is by-passed - unfortunately,
197		// this is implementation specific (and I found no docs
198		// for the Apple OF disk-label usage, of course)
199
200		// SUN's OpenBoot:
201		//strcpy(path + strlen(path), ":nolabel");
202		// Apple:
203		if (gMachine & MACHINE_MAC)
204			strcpy(path + strlen(path), ":0");
205
206		printf("\t%s\n", path);
207
208		intptr_t handle = of_open(path);
209		if (handle == OF_FAILED) {
210			puts("\t\t(failed)");
211			continue;
212		}
213
214		Handle *device = new(nothrow) Handle(handle);
215		printf("\t\t(could open device, handle = %p, node = %p)\n",
216			(void *)handle, device);
217
218		devicesList->Add(device);
219	}
220	printf("\t(loop ended with %ld)\n", status);
221
222	return B_OK;
223}
224
225
226status_t
227platform_register_boot_device(Node *device)
228{
229	disk_identifier disk;
230
231	disk.bus_type = UNKNOWN_BUS;
232	disk.device_type = UNKNOWN_DEVICE;
233	disk.device.unknown.size = device->Size();
234
235	gBootVolume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, &disk,
236		sizeof(disk_identifier));
237
238	return B_OK;
239}
240
241