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