1*2e601613SDavid Gibson /* 2*2e601613SDavid Gibson * Copyright (C) Paul Mackerras 1997. 3*2e601613SDavid Gibson * 4*2e601613SDavid Gibson * This program is free software; you can redistribute it and/or 5*2e601613SDavid Gibson * modify it under the terms of the GNU General Public License 6*2e601613SDavid Gibson * as published by the Free Software Foundation; either version 7*2e601613SDavid Gibson * 2 of the License, or (at your option) any later version. 8*2e601613SDavid Gibson */ 9*2e601613SDavid Gibson #include <stddef.h> 10*2e601613SDavid Gibson #include "types.h" 11*2e601613SDavid Gibson #include "elf.h" 12*2e601613SDavid Gibson #include "string.h" 13*2e601613SDavid Gibson #include "stdio.h" 14*2e601613SDavid Gibson #include "page.h" 15*2e601613SDavid Gibson #include "ops.h" 16*2e601613SDavid Gibson 17*2e601613SDavid Gibson #include "of.h" 18*2e601613SDavid Gibson 19*2e601613SDavid Gibson static int (*prom) (void *); 20*2e601613SDavid Gibson 21*2e601613SDavid Gibson void of_init(void *promptr) 22*2e601613SDavid Gibson { 23*2e601613SDavid Gibson prom = (int (*)(void *))promptr; 24*2e601613SDavid Gibson } 25*2e601613SDavid Gibson 26*2e601613SDavid Gibson int of_call_prom(const char *service, int nargs, int nret, ...) 27*2e601613SDavid Gibson { 28*2e601613SDavid Gibson int i; 29*2e601613SDavid Gibson struct prom_args { 30*2e601613SDavid Gibson const char *service; 31*2e601613SDavid Gibson int nargs; 32*2e601613SDavid Gibson int nret; 33*2e601613SDavid Gibson unsigned int args[12]; 34*2e601613SDavid Gibson } args; 35*2e601613SDavid Gibson va_list list; 36*2e601613SDavid Gibson 37*2e601613SDavid Gibson args.service = service; 38*2e601613SDavid Gibson args.nargs = nargs; 39*2e601613SDavid Gibson args.nret = nret; 40*2e601613SDavid Gibson 41*2e601613SDavid Gibson va_start(list, nret); 42*2e601613SDavid Gibson for (i = 0; i < nargs; i++) 43*2e601613SDavid Gibson args.args[i] = va_arg(list, unsigned int); 44*2e601613SDavid Gibson va_end(list); 45*2e601613SDavid Gibson 46*2e601613SDavid Gibson for (i = 0; i < nret; i++) 47*2e601613SDavid Gibson args.args[nargs+i] = 0; 48*2e601613SDavid Gibson 49*2e601613SDavid Gibson if (prom(&args) < 0) 50*2e601613SDavid Gibson return -1; 51*2e601613SDavid Gibson 52*2e601613SDavid Gibson return (nret > 0)? args.args[nargs]: 0; 53*2e601613SDavid Gibson } 54*2e601613SDavid Gibson 55*2e601613SDavid Gibson static int of_call_prom_ret(const char *service, int nargs, int nret, 56*2e601613SDavid Gibson unsigned int *rets, ...) 57*2e601613SDavid Gibson { 58*2e601613SDavid Gibson int i; 59*2e601613SDavid Gibson struct prom_args { 60*2e601613SDavid Gibson const char *service; 61*2e601613SDavid Gibson int nargs; 62*2e601613SDavid Gibson int nret; 63*2e601613SDavid Gibson unsigned int args[12]; 64*2e601613SDavid Gibson } args; 65*2e601613SDavid Gibson va_list list; 66*2e601613SDavid Gibson 67*2e601613SDavid Gibson args.service = service; 68*2e601613SDavid Gibson args.nargs = nargs; 69*2e601613SDavid Gibson args.nret = nret; 70*2e601613SDavid Gibson 71*2e601613SDavid Gibson va_start(list, rets); 72*2e601613SDavid Gibson for (i = 0; i < nargs; i++) 73*2e601613SDavid Gibson args.args[i] = va_arg(list, unsigned int); 74*2e601613SDavid Gibson va_end(list); 75*2e601613SDavid Gibson 76*2e601613SDavid Gibson for (i = 0; i < nret; i++) 77*2e601613SDavid Gibson args.args[nargs+i] = 0; 78*2e601613SDavid Gibson 79*2e601613SDavid Gibson if (prom(&args) < 0) 80*2e601613SDavid Gibson return -1; 81*2e601613SDavid Gibson 82*2e601613SDavid Gibson if (rets != (void *) 0) 83*2e601613SDavid Gibson for (i = 1; i < nret; ++i) 84*2e601613SDavid Gibson rets[i-1] = args.args[nargs+i]; 85*2e601613SDavid Gibson 86*2e601613SDavid Gibson return (nret > 0)? args.args[nargs]: 0; 87*2e601613SDavid Gibson } 88*2e601613SDavid Gibson 89*2e601613SDavid Gibson /* returns true if s2 is a prefix of s1 */ 90*2e601613SDavid Gibson static int string_match(const char *s1, const char *s2) 91*2e601613SDavid Gibson { 92*2e601613SDavid Gibson for (; *s2; ++s2) 93*2e601613SDavid Gibson if (*s1++ != *s2) 94*2e601613SDavid Gibson return 0; 95*2e601613SDavid Gibson return 1; 96*2e601613SDavid Gibson } 97*2e601613SDavid Gibson 98*2e601613SDavid Gibson /* 99*2e601613SDavid Gibson * Older OF's require that when claiming a specific range of addresses, 100*2e601613SDavid Gibson * we claim the physical space in the /memory node and the virtual 101*2e601613SDavid Gibson * space in the chosen mmu node, and then do a map operation to 102*2e601613SDavid Gibson * map virtual to physical. 103*2e601613SDavid Gibson */ 104*2e601613SDavid Gibson static int need_map = -1; 105*2e601613SDavid Gibson static ihandle chosen_mmu; 106*2e601613SDavid Gibson static phandle memory; 107*2e601613SDavid Gibson 108*2e601613SDavid Gibson static int check_of_version(void) 109*2e601613SDavid Gibson { 110*2e601613SDavid Gibson phandle oprom, chosen; 111*2e601613SDavid Gibson char version[64]; 112*2e601613SDavid Gibson 113*2e601613SDavid Gibson oprom = finddevice("/openprom"); 114*2e601613SDavid Gibson if (oprom == (phandle) -1) 115*2e601613SDavid Gibson return 0; 116*2e601613SDavid Gibson if (getprop(oprom, "model", version, sizeof(version)) <= 0) 117*2e601613SDavid Gibson return 0; 118*2e601613SDavid Gibson version[sizeof(version)-1] = 0; 119*2e601613SDavid Gibson printf("OF version = '%s'\r\n", version); 120*2e601613SDavid Gibson if (!string_match(version, "Open Firmware, 1.") 121*2e601613SDavid Gibson && !string_match(version, "FirmWorks,3.")) 122*2e601613SDavid Gibson return 0; 123*2e601613SDavid Gibson chosen = finddevice("/chosen"); 124*2e601613SDavid Gibson if (chosen == (phandle) -1) { 125*2e601613SDavid Gibson chosen = finddevice("/chosen@0"); 126*2e601613SDavid Gibson if (chosen == (phandle) -1) { 127*2e601613SDavid Gibson printf("no chosen\n"); 128*2e601613SDavid Gibson return 0; 129*2e601613SDavid Gibson } 130*2e601613SDavid Gibson } 131*2e601613SDavid Gibson if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) { 132*2e601613SDavid Gibson printf("no mmu\n"); 133*2e601613SDavid Gibson return 0; 134*2e601613SDavid Gibson } 135*2e601613SDavid Gibson memory = (ihandle) of_call_prom("open", 1, 1, "/memory"); 136*2e601613SDavid Gibson if (memory == (ihandle) -1) { 137*2e601613SDavid Gibson memory = (ihandle) of_call_prom("open", 1, 1, "/memory@0"); 138*2e601613SDavid Gibson if (memory == (ihandle) -1) { 139*2e601613SDavid Gibson printf("no memory node\n"); 140*2e601613SDavid Gibson return 0; 141*2e601613SDavid Gibson } 142*2e601613SDavid Gibson } 143*2e601613SDavid Gibson printf("old OF detected\r\n"); 144*2e601613SDavid Gibson return 1; 145*2e601613SDavid Gibson } 146*2e601613SDavid Gibson 147*2e601613SDavid Gibson void *of_claim(unsigned long virt, unsigned long size, unsigned long align) 148*2e601613SDavid Gibson { 149*2e601613SDavid Gibson int ret; 150*2e601613SDavid Gibson unsigned int result; 151*2e601613SDavid Gibson 152*2e601613SDavid Gibson if (need_map < 0) 153*2e601613SDavid Gibson need_map = check_of_version(); 154*2e601613SDavid Gibson if (align || !need_map) 155*2e601613SDavid Gibson return (void *) of_call_prom("claim", 3, 1, virt, size, align); 156*2e601613SDavid Gibson 157*2e601613SDavid Gibson ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory, 158*2e601613SDavid Gibson align, size, virt); 159*2e601613SDavid Gibson if (ret != 0 || result == -1) 160*2e601613SDavid Gibson return (void *) -1; 161*2e601613SDavid Gibson ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu, 162*2e601613SDavid Gibson align, size, virt); 163*2e601613SDavid Gibson /* 0x12 == coherent + read/write */ 164*2e601613SDavid Gibson ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu, 165*2e601613SDavid Gibson 0x12, size, virt, virt); 166*2e601613SDavid Gibson return (void *) virt; 167*2e601613SDavid Gibson } 168*2e601613SDavid Gibson 169*2e601613SDavid Gibson void of_exit(void) 170*2e601613SDavid Gibson { 171*2e601613SDavid Gibson of_call_prom("exit", 0, 0); 172*2e601613SDavid Gibson } 173