X-Git-Url: http://git.ozlabs.org/?p=yaboot.git;a=blobdiff_plain;f=second%2Fprom.c;h=119d0f363cabbc971f259b6e6f4c61b27cbbaf4c;hp=82e615146ab39ad651953f96321d8bf8b218d23e;hb=ba5849c566fd9e1d0765d734d1871bc48c12350f;hpb=2ad0d7649e5042cad43a16b4a03bf53f39948316 diff --git a/second/prom.c b/second/prom.c index 82e6151..119d0f3 100644 --- a/second/prom.c +++ b/second/prom.c @@ -1,7 +1,7 @@ /* * prom.c - Routines for talking to the Open Firmware PROM * - * Copyright (C) 2001 Ethan Benson + * Copyright (C) 2001, 2002 Ethan Benson * * Copyright (C) 1999 Benjamin Herrenschmidt * @@ -33,15 +33,16 @@ #include "asm/processor.h" #include "errors.h" #include "debug.h" +#include "string.h" #define READ_BLOCKS_USE_READ 1 +static int yaboot_debug; + prom_entry prom; ihandle prom_stdin, prom_stdout; -//extern int vsprintf(char *buf, const char *fmt, va_list args); - static ihandle prom_mem, prom_mmu; static ihandle prom_chosen, prom_options; @@ -58,7 +59,7 @@ call_prom (const char *service, int nargs, int nret, ...) va_list list; int i; struct prom_args prom_args; - + prom_args.service = service; prom_args.nargs = nargs; prom_args.nret = nret; @@ -82,7 +83,7 @@ call_prom_return (const char *service, int nargs, int nret, ...) int i; void* result; struct prom_args prom_args; - + prom_args.service = service; prom_args.nargs = nargs; prom_args.nret = nret; @@ -111,7 +112,7 @@ call_method_1 (char *method, prom_handle h, int nargs, ...) va_list list; int i; struct prom_args prom_args; - + prom_args.service = "call-method"; prom_args.nargs = nargs+2; prom_args.nret = 2; @@ -123,7 +124,7 @@ call_method_1 (char *method, prom_handle h, int nargs, ...) va_end(list); prom_args.args[2+nargs] = 0; prom_args.args[2+nargs+1] = 0; - + prom (&prom_args); if (prom_args.args[2+nargs] != 0) @@ -153,6 +154,18 @@ prom_getprop (prom_handle pack, char *name, void *mem, int len) return (int)call_prom ("getprop", 4, 1, pack, name, mem, len); } +int +prom_getproplen(prom_handle pack, const char *name) +{ + return (int)call_prom("getproplen", 2, 1, pack, name); +} + +int +prom_setprop (prom_handle pack, char *name, void *mem, int len) +{ + return (int)call_prom ("setprop", 4, 1, pack, name, mem, len); +} + int prom_get_chosen (char *name, void *mem, int len) { @@ -167,6 +180,14 @@ prom_get_options (char *name, void *mem, int len) return prom_getprop (prom_options, name, mem, len); } +int +prom_set_options (char *name, void *mem, int len) +{ + if (prom_options == (void *)-1) + return -1; + return prom_setprop (prom_options, name, mem, len); +} + int prom_get_devtype (char *device) { @@ -174,6 +195,9 @@ prom_get_devtype (char *device) int result; char tmp[64]; + if (strstr(device, TOK_ISCSI)) + device = strcpy(tmp, "/vdevice/gscsi/disk"); + /* Find OF device phandle */ dev = prom_finddevice(device); if (dev == PROM_INVALID_HANDLE) { @@ -215,17 +239,20 @@ prom_init (prom_entry pp) if (prom_get_chosen ("mmu", &prom_mmu, sizeof(prom_mmu)) <= 0) prom_abort ("\nCan't get mmu handle"); + yaboot_debug = 0; + prom_get_options("linux,yaboot-debug", &yaboot_debug, sizeof(yaboot_debug)); + // move cursor to fresh line prom_printf ("\n"); /* Add a few OF methods (thanks Darwin) */ #if DEBUG prom_printf ("Adding OF methods...\n"); -#endif +#endif prom_interpret ( /* All values in this forth code are in hex */ - "hex " + "hex " /* Those are a few utilities ripped from Apple */ ": D2NIP decode-int nip nip ;\r" // A useful function to save space ": GPP$ get-package-property 0= ;\r" // Another useful function to save space @@ -278,7 +305,7 @@ prom_read (prom_handle file, void *buf, int n) { int result = 0; int retries = 10; - + if (n == 0) return 0; while(--retries) { @@ -287,7 +314,7 @@ prom_read (prom_handle file, void *buf, int n) break; call_prom("interpret", 1, 1, " 10 ms"); } - + return result; } @@ -330,7 +357,7 @@ prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer) #if READ_BLOCKS_USE_READ int status; unsigned int blksize; - + blksize = prom_getblksize(dev); if (blksize <= 1) blksize = 512; @@ -339,16 +366,16 @@ prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer) return 0; prom_printf("Can't seek to 0x%x\n", blockNum * blksize); } - + status = prom_read(dev, buffer, blockCount * blksize); // prom_printf("prom_readblocks, bl: %d, cnt: %d, status: %d\n", // blockNum, blockCount, status); return status == (blockCount * blksize); -#else +#else int result; int retries = 10; - + if (blockCount == 0) return blockCount; while(--retries) { @@ -357,24 +384,22 @@ prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer) break; call_prom("interpret", 1, 1, " 10 ms"); } - + return result; -#endif +#endif } int prom_getchar () { - char c[4]; + char c; int a; - while ((a = (int)call_prom ("read", 3, 1, prom_stdin, c, 4)) == 0) + while ((a = (int)call_prom ("read", 3, 1, prom_stdin, &c, 1)) == 0) ; if (a == -1) prom_abort ("EOF on console\n"); - if (a == 3 && c[0] == '\e' && c[1] == '[') - return 0x100 | c[2]; - return c[0]; + return c; } int @@ -399,20 +424,20 @@ prom_puts (prom_handle file, char *s) { const char *p, *q; - for (p = s; *p != 0; p = q) + for (p = s; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) ; if (q > p) call_prom ("write", 3, 1, file, p, q - p); - if (*q != 0) + if (*q != 0) { ++q; call_prom ("write", 3, 1, file, "\r\n", 2); } } } - + void prom_vfprintf (prom_handle file, char *fmt, va_list ap) { @@ -447,6 +472,19 @@ prom_printf (char *fmt, ...) va_end (ap); } +void +prom_debug (char *fmt, ...) +{ + va_list ap; + + if (!yaboot_debug) + return; + + va_start (ap, fmt); + prom_vfprintf (prom_stdout, fmt, ap); + va_end (ap); +} + void prom_perror (int error, char *filename) { @@ -459,7 +497,7 @@ prom_perror (int error, char *filename) else if (error == FILE_IOERR) prom_printf("%s: Input/output error\n", filename); else if (error == FILE_BAD_PATH) - prom_printf("%s: Path too long\n", filename); + prom_printf("%s: Path too long\n", filename); else if (error == FILE_ERR_BAD_TYPE) prom_printf("%s: Not a regular file\n", filename); else if (error == FILE_ERR_NOTDIR) @@ -489,8 +527,6 @@ prom_readline (char *prompt, char *buf, int len) while (i < len-1 && (c = prom_getchar ()) != '\r') { - if (c >= 0x100) - continue; if (c == 8) { if (i > 0) @@ -544,32 +580,46 @@ prom_sleep (int seconds) while (prom_getms() <= end); } +/* if address given is claimed look for other addresses to get the needed + * space before giving up + */ +void * +prom_claim_chunk(void *virt, unsigned int size, unsigned int align) +{ + void *found, *addr; + for(addr=virt; addr <= (void*)PROM_CLAIM_MAX_ADDR; + addr+=(0x100000/sizeof(addr))) { + found = call_prom("claim", 3, 1, addr, size, 0); + if (found != (void *)-1) { + prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)addr, (int)found); + return(found); + } + } + prom_printf("ERROR: claim of 0x%x in range 0x%x-0x%x failed\n", size, (int)virt, PROM_CLAIM_MAX_ADDR); + return((void*)-1); +} + void * prom_claim (void *virt, unsigned int size, unsigned int align) { - return call_prom ("claim", 3, 1, virt, size, align); + void *ret; + + ret = call_prom ("claim", 3, 1, virt, size, align); + if (ret == (void *)-1) + prom_printf("ERROR: claim of 0x%x at 0x%x failed\n", size, (int)virt); + else + prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret); + + return ret; } void prom_release(void *virt, unsigned int size) { -// call_prom ("release", 2, 1, virt, size); - /* release in not enough, it needs also an unmap call. This bit of forth - * code inspired from Darwin's bootloader but could be replaced by direct - * calls to the MMU package if needed - */ - call_prom ("interpret", 3, 1, -#if DEBUG - ".\" ReleaseMem:\" 2dup . . cr " -#endif - "over \" translate\" ^mmu " // Find out physical base - "^on0 " // Bail if translation failed - "drop " // Leaving phys on top of stack - "2dup \" unmap\" ^mmu " // Unmap the space first - "2dup \" release\" ^mmu " // Then free the virtual pages - "\" release\" ^mem " // Then free the physical pages - ,size, virt - ); + void *ret; + + ret = call_prom ("release", 2, 0, virt, size); + prom_debug("release of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret); } void @@ -625,10 +675,173 @@ prom_getms(void) void prom_pause(void) { + prom_print_available(); call_prom("enter", 0, 0); } -/* +/* + * prom_get_netinfo() + * returns the packet with all needed info for netboot + */ +struct bootp_packet * prom_get_netinfo (void) +{ + void *bootp_response = NULL; + char *propname; + struct bootp_packet *packet; + /* struct bootp_packet contains a VLA, so sizeof won't work. + the VLA /must/ be the last field in the structure so use it's + offset as a good estimate of the packet size */ + size_t packet_size = offsetof(struct bootp_packet, options); + int i = 0, size, offset = 0; + prom_handle chosen; +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + + chosen = prom_finddevice("/chosen"); + if (chosen < 0) { + DEBUG_F("chosen=%d\n", chosen); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) { + propname = bootp_response_properties[i].name; + size = prom_getproplen(chosen, propname); + if (size <= 0) + continue; + + DEBUG_F("using /chosen/%s\n", propname); + offset = bootp_response_properties[i].offset; + break; + } + + if (size <= 0) + return NULL; + + if (packet_size > size - offset) { + prom_printf("Malformed %s property?\n", propname); + return NULL; + } + + bootp_response = malloc(size); + if (!bootp_response) + return NULL; + + if (prom_getprop(chosen, propname, bootp_response, size) < 0) + return NULL; + + packet = bootp_response + offset; + return packet; +} + +/* + * prom_get_mac() + * returns the mac addr of an net card + */ +char * prom_get_mac (struct bootp_packet * packet) +{ + char * conf_path; + int i; + + if (!packet) + return NULL; + + /* 3 chars per byte in chaddr + \0 */ + conf_path = malloc(packet->hlen * 3 + 1); + if (!conf_path) + return NULL; + sprintf(conf_path, "%02x", packet->chaddr[0]); + + for (i = 1; i < packet->hlen; i++) { + char tmp[4]; + sprintf(tmp, "-%02x", packet->chaddr[i]); + strcat(conf_path, tmp); + } + + return conf_path; +} + +/* + * prom_get_ip() + * returns the ip addr of an net card + */ +char * prom_get_ip (struct bootp_packet * packet) +{ + char * conf_path; + + if (!packet) + return NULL; + + /* 8 chars in yiaddr + \0 */ + conf_path = malloc(9); + if (!conf_path) + return NULL; + sprintf(conf_path, "%08x", packet->yiaddr); + + return conf_path; +} + +/* We call this too early to use malloc, 128 cells should be large enough */ +#define NR_AVAILABLE 128 + +void prom_print_available(void) +{ + prom_handle root; + unsigned int addr_cells, size_cells; + ihandle mem; + unsigned int available[NR_AVAILABLE]; + unsigned int len; + unsigned int *p; + + if (!yaboot_debug) + return; + + root = prom_finddevice("/"); + if (!root) + return; + + addr_cells = 2; + prom_getprop(root, "#address-cells", &addr_cells, sizeof(addr_cells)); + + size_cells = 1; + prom_getprop(root, "#size-cells", &size_cells, sizeof(size_cells)); + + mem = prom_finddevice("/memory@0"); + if (mem == PROM_INVALID_HANDLE) + return; + + len = prom_getprop(mem, "available", available, sizeof(available)); + if (len == -1) + return; + len /= 4; + + prom_printf("\nAvailable memory ranges:\n"); + + p = available; + while (len > 0) { + unsigned int addr, size; + + /* + * Since we are in 32bit mode it should be safe to only print the + * bottom 32bits of each range. + */ + p += (addr_cells - 1); + addr = *p; + p++; + + p += (size_cells - 1); + size = *p; + p++; + + if (size) + prom_printf("0x%08x-0x%08x (%3d MB)\n", addr, addr + size, + size/1024/1024); + + len -= (addr_cells + size_cells); + } + + prom_printf("\n"); +} + +/* * Local variables: * c-file-style: "k&r" * c-basic-offset: 5