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