mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-27 16:58:09 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
570 lines
11 KiB
C
570 lines
11 KiB
C
/*
|
|
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
|
|
* Reserved. This file contains Original Code and/or Modifications of
|
|
* Original Code as defined in and that are subject to the Apple Public
|
|
* Source License Version 1.1 (the "License"). You may not use this file
|
|
* except in compliance with the License. Please obtain a copy of the
|
|
* License at http://www.apple.com/publicsource and read it before using
|
|
* this file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
|
|
* License for the specific language governing rights and limitations
|
|
* under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*/
|
|
/*
|
|
* Copyright 1993 NeXT, Inc.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
//#import "libsaio.h"
|
|
//#import "bootstruct.h"
|
|
//#import <driverkit/configTablePrivate.h>
|
|
|
|
extern char *Language;
|
|
extern char *LoadableFamilies;
|
|
|
|
static void eatThru(char val, char **table_p);
|
|
|
|
static __inline INTN isspace(char c)
|
|
{
|
|
return (c == ' ' || c == '\t');
|
|
}
|
|
|
|
/*
|
|
* Compare a string to a key with quoted characters
|
|
*/
|
|
static __inline int
|
|
keyncmp(char *str, char *key, INTN n)
|
|
{
|
|
INTN c;
|
|
while (n--) {
|
|
c = *key++;
|
|
if (c == '\\') {
|
|
switch(c = *key++) {
|
|
case 'n':
|
|
c = '\n';
|
|
break;
|
|
case 'r':
|
|
c = '\r';
|
|
break;
|
|
case 't':
|
|
c = '\t';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (c == '\"') {
|
|
/* Premature end of key */
|
|
return 1;
|
|
}
|
|
if (c != *str++) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void eatThru(char val, char **table_p)
|
|
{
|
|
register char *table = *table_p;
|
|
register BOOL found = NO;
|
|
|
|
while (*table && !found)
|
|
{
|
|
if (*table == '\\') table += 2;
|
|
else
|
|
{
|
|
if (*table == val) found = YES;
|
|
table++;
|
|
}
|
|
}
|
|
*table_p = table;
|
|
}
|
|
|
|
char *
|
|
newStringFromList(
|
|
char **list,
|
|
INTN* size
|
|
)
|
|
{
|
|
char *begin = *list, *end;
|
|
char *newstr;
|
|
INTN newsize = *size;
|
|
|
|
while (*begin && newsize && isspace(*begin)) {
|
|
begin++;
|
|
newsize--;
|
|
}
|
|
end = begin;
|
|
while (*end && newsize && !isspace(*end)) {
|
|
end++;
|
|
newsize--;
|
|
}
|
|
if (begin == end)
|
|
return 0;
|
|
newstr = malloc(end - begin + 1);
|
|
strncpy(newstr, begin, end - begin);
|
|
*list = end;
|
|
*size = newsize;
|
|
return newstr;
|
|
}
|
|
|
|
/*
|
|
* compress == compress escaped characters to one character
|
|
*/
|
|
int stringLength(char *table, INTN compress)
|
|
{
|
|
int ret = 0;
|
|
|
|
while (*table)
|
|
{
|
|
if (*table == '\\')
|
|
{
|
|
table += 2;
|
|
ret += 1 + (compress ? 0 : 1);
|
|
}
|
|
else
|
|
{
|
|
if (*table == '\"') return ret;
|
|
ret++;
|
|
table++;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
// looks in table for strings of format << "key" = "value"; >>
|
|
// or << "key"; >>
|
|
BOOL getValueForStringTableKey(char *table, char *key, char **val, INTN *size)
|
|
{
|
|
INTN keyLength;
|
|
char *tableKey;
|
|
|
|
do
|
|
{
|
|
eatThru('\"',&table);
|
|
tableKey = table;
|
|
keyLength = strlen(key);
|
|
if (keyLength &&
|
|
(stringLength(table,1) == keyLength) &&
|
|
(keyncmp(key, table, keyLength) == 0))
|
|
{
|
|
INTN c;
|
|
|
|
/* found the key; now look for either
|
|
* '=' or ';'
|
|
*/
|
|
while (c = *table) {
|
|
++table;
|
|
if (c == '\\') {
|
|
++table;
|
|
continue;
|
|
} else if (c == '=' || c == ';') {
|
|
break;
|
|
}
|
|
}
|
|
if (c == ';') {
|
|
table = tableKey;
|
|
} else {
|
|
eatThru('\"',&table);
|
|
}
|
|
*val = table;
|
|
*size = stringLength(table,0);
|
|
return YES;
|
|
}
|
|
|
|
eatThru(';',&table);
|
|
|
|
} while (*table);
|
|
|
|
return NO;
|
|
}
|
|
|
|
|
|
/*
|
|
* Returns a new malloc'ed string if one is found
|
|
* in the string table matching 'key'. Also translates
|
|
* \n escapes in the string.
|
|
*/
|
|
char *newStringForStringTableKey(
|
|
char *table,
|
|
char *key
|
|
)
|
|
{
|
|
char *val, *newstr, *p;
|
|
INTN size;
|
|
|
|
if (getValueForStringTableKey(table, key, &val, &size)) {
|
|
newstr = malloc(size+1);
|
|
for (p = newstr; size; size--, p++, val++) {
|
|
if ((*p = *val) == '\\') {
|
|
switch (*++val) {
|
|
case 'r':
|
|
*p = '\r';
|
|
break;
|
|
case 'n':
|
|
*p = '\n';
|
|
break;
|
|
case 't':
|
|
*p = '\t';
|
|
break;
|
|
default:
|
|
*p = *val;
|
|
break;
|
|
}
|
|
size--;
|
|
}
|
|
}
|
|
*p = '\0';
|
|
return newstr;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
char *
|
|
newStringForKey(char *key)
|
|
{
|
|
char *val, *newstr;
|
|
INTN size;
|
|
|
|
if (getValueForKey(key, &val, &size) && size) {
|
|
newstr = malloc(size + 1);
|
|
strncpy(newstr, val, size);
|
|
return newstr;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* parse a command line
|
|
* in the form: [<argument> ...] [<option>=<value> ...]
|
|
* both <option> and <value> must be either composed of
|
|
* non-whitespace characters, or enclosed in quotes.
|
|
*/
|
|
|
|
static char *getToken(char *line, char **begin, INTN *len)
|
|
{
|
|
if (*line == '\"') {
|
|
*begin = ++line;
|
|
while (*line && *line != '\"')
|
|
line++;
|
|
*len = line++ - *begin;
|
|
} else {
|
|
*begin = line;
|
|
while (*line && !isspace(*line) && *line != '=')
|
|
line++;
|
|
*len = line - *begin;
|
|
}
|
|
return line;
|
|
}
|
|
|
|
BOOL getValueForBootKey(char *line, char *match, char **matchval, INTN *len)
|
|
{
|
|
char *key, *value;
|
|
INTN key_len, value_len;
|
|
|
|
while (*line) {
|
|
/* look for keyword or argument */
|
|
while (isspace(*line)) line++;
|
|
|
|
/* now look for '=' or whitespace */
|
|
line = getToken(line, &key, &key_len);
|
|
/* line now points to '=' or space */
|
|
if (!isspace(*line++)) {
|
|
line = getToken(line, &value, &value_len);
|
|
if ((strlen(match) == key_len)
|
|
&& strncmp(match, key, key_len) == 0) {
|
|
*matchval = value;
|
|
*len = value_len;
|
|
return YES;
|
|
}
|
|
}
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
BOOL getBoolForKey(
|
|
char *key
|
|
)
|
|
{
|
|
char *val;
|
|
INTN, size;
|
|
|
|
if (getValueForKey(key, &val, &size) && (size >= 1) &&
|
|
val[0] == 'Y' || val[0] == 'y')
|
|
return YES;
|
|
return NO;
|
|
}
|
|
|
|
BOOL getValueForKey(
|
|
char *key,
|
|
char **val,
|
|
INTN *size
|
|
)
|
|
{
|
|
if (getValueForBootKey(bootArgs->bootString, key, val, size))
|
|
return YES;
|
|
else if (getValueForStringTableKey(bootArgs->config, key, val, size))
|
|
return YES;
|
|
|
|
return NO;
|
|
}
|
|
|
|
#define LOCALIZABLE \
|
|
"/usr/Devices/%s.config/%s.lproj/Localizable.strings"
|
|
|
|
char *
|
|
loadLocalizableStrings(
|
|
char *name
|
|
)
|
|
{
|
|
char buf[256], *config;
|
|
register INTN count, fd;
|
|
|
|
sprintf(buf, LOCALIZABLE, name, Language);
|
|
if ((fd = open(buf,0)) < 0) {
|
|
sprintf(buf, LOCALIZABLE, name, "English");
|
|
if ((fd = open(buf,0)) < 0)
|
|
return 0;
|
|
}
|
|
count = file_size(fd);
|
|
config = malloc(count);
|
|
count = read(fd, config, count);
|
|
close(fd);
|
|
if (count <= 0) {
|
|
free(config);
|
|
return 0;
|
|
}
|
|
return config;
|
|
}
|
|
|
|
char *
|
|
bundleLongName(
|
|
char *bundleName
|
|
)
|
|
{
|
|
char *table, *name, *val;
|
|
INTN, size;
|
|
|
|
if ((table = loadLocalizableStrings(bundleName)) != 0 &&
|
|
getValueForStringTableKey(table,"Long Name", &val, &size) == YES) {
|
|
name = malloc(size+1);
|
|
strncpy(name, val, size);
|
|
free(table);
|
|
} else {
|
|
name = newString(bundleName);
|
|
}
|
|
return name;
|
|
}
|
|
|
|
int sysConfigValid;
|
|
|
|
|
|
/*
|
|
* Returns 0 if file loaded OK,
|
|
* -1 if file was not loaded
|
|
* Does not print error messages.
|
|
* Returns pointer to table in memory in *table.
|
|
*/
|
|
int
|
|
loadConfigFile( char *configFile, char **table, INTN allocTable)
|
|
{
|
|
char *configPtr = bootArgs->configEnd;
|
|
INTN fd, count;
|
|
|
|
/* Read config file into memory */
|
|
if ((fd = open(configFile, 0)) >= 0)
|
|
{
|
|
if (allocTable) {
|
|
configPtr = malloc(file_size(fd)+2);
|
|
} else {
|
|
if ((configPtr - bootArgs->config) > CONFIG_SIZE) {
|
|
error("No room in memory for config file %s\n",configFile);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
localPrintf("Reading config: %s\n",configFile);
|
|
}
|
|
if (table) *table = configPtr;
|
|
count = read(fd, configPtr, IO_CONFIG_DATA_SIZE);
|
|
close(fd);
|
|
|
|
configPtr += count;
|
|
*configPtr++ = 0;
|
|
*configPtr = 0;
|
|
if (!allocTable)
|
|
bootArgs->configEnd = configPtr;
|
|
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Returns 0 if requested config files were loaded,
|
|
* 1 if default files were loaded,
|
|
* -1 if no files were loaded.
|
|
* Prints error message if files cannot be loaded.
|
|
*/
|
|
|
|
int
|
|
loadConfigDir(
|
|
char *bundleName, // bundle directory name (e.g. "System.config")
|
|
INTN useDefault, // use Default.table instead of instance tables
|
|
char **table, // returns pointer to config table
|
|
INTN allocTable // malloc the table and return in *table
|
|
)
|
|
{
|
|
char *buf;
|
|
INTN i, ret;
|
|
|
|
buf = malloc(256);
|
|
ret = 0;
|
|
|
|
// load up to 99 instance tables
|
|
for (i=0; i < 99; i++) {
|
|
sprintf(buf, "%s%s.config/Instance%d.table", IO_CONFIG_DIR,
|
|
bundleName, i);
|
|
if (useDefault || (loadConfigFile(buf, table, allocTable) != 0)) {
|
|
if (i == 0) {
|
|
// couldn't load first instance table;
|
|
// try the default table
|
|
sprintf(buf, "%s%s.config/%s", IO_CONFIG_DIR, bundleName,
|
|
IO_DEFAULT_TABLE_FILENAME);
|
|
if (loadConfigFile(buf, table, allocTable) == 0) {
|
|
ret = 1;
|
|
} else {
|
|
if (!allocTable)
|
|
error("Config file \"%s\" not found\n", buf);
|
|
ret = -1;
|
|
}
|
|
}
|
|
// we must be done.
|
|
break;
|
|
}
|
|
}
|
|
free(buf);
|
|
return ret;
|
|
}
|
|
|
|
|
|
#define SYSTEM_DEFAULT_FILE \
|
|
IO_SYSTEM_CONFIG_DIR IO_DEFAULT_TABLE_FILENAME
|
|
#define SYSTEM_CONFIG "System"
|
|
#define LP '('
|
|
#define RP ')'
|
|
|
|
/* Returns 0 if requested config files were loaded,
|
|
* 1 if default files were loaded,
|
|
* -1 if no files were loaded.
|
|
* Prints error message if files cannot be loaded.
|
|
*/
|
|
int
|
|
loadSystemConfig(
|
|
char *which,
|
|
INTN size
|
|
)
|
|
{
|
|
char *buf, *bp, *cp;
|
|
INTN ret, len, doDefault=0;
|
|
|
|
buf = bp = malloc(256);
|
|
if (which && size)
|
|
{
|
|
for(cp = which, len = size; len && *cp && *cp != LP; cp++, len--) ;
|
|
if (*cp == LP) {
|
|
while (len-- && *cp && *cp++ != RP) ;
|
|
/* cp now points past device */
|
|
strncpy(buf,which,cp - which);
|
|
bp += cp - which;
|
|
} else {
|
|
cp = which;
|
|
len = size;
|
|
}
|
|
if (*cp != '/') {
|
|
strcpy(bp, IO_SYSTEM_CONFIG_DIR);
|
|
strncat(bp, cp, len);
|
|
if (strncmp(cp + len - strlen(IO_TABLE_EXTENSION),
|
|
IO_TABLE_EXTENSION, strlen(IO_TABLE_EXTENSION)) != 0)
|
|
strcat(bp, IO_TABLE_EXTENSION);
|
|
} else {
|
|
strncpy(bp, cp, len);
|
|
bp[size] = '\0';
|
|
}
|
|
if (strcmp(bp, SYSTEM_DEFAULT_FILE) == 0)
|
|
doDefault = 1;
|
|
ret = loadConfigFile(bp = buf, 0, 0);
|
|
} else {
|
|
ret = loadConfigDir((bp = SYSTEM_CONFIG), 0, 0, 0);
|
|
}
|
|
if (ret < 0) {
|
|
error("System config file '%s' not found\n", bp);
|
|
} else
|
|
sysConfigValid = 1;
|
|
free(buf);
|
|
return (ret < 0 ? ret : doDefault);
|
|
}
|
|
|
|
|
|
int
|
|
loadOtherConfigs(
|
|
INTN useDefault
|
|
)
|
|
{
|
|
char *val, *table;
|
|
INTN count;
|
|
char *string;
|
|
INTN fd, ret;
|
|
|
|
if (getValueForKey( "Boot Drivers", &val, &count))
|
|
{
|
|
while (string = newStringFromList(&val, &count)) {
|
|
ret = loadConfigDir(string, useDefault, &table, 0);
|
|
if (ret >= 0) {
|
|
if ((fd = openDriverReloc(string)) >= 0) {
|
|
localPrintf("Loading binary for %s\n",string);
|
|
if (loadDriver(string, fd) < 0)
|
|
error("Error loading driver %s\n",string);
|
|
close(fd);
|
|
}
|
|
driverWasLoaded(string, table);
|
|
free(string);
|
|
} else {
|
|
driverIsMissing(string);
|
|
}
|
|
if (ret == 1)
|
|
useDefault = 1; // use defaults from now on
|
|
}
|
|
} else {
|
|
error("Warning: No active drivers specified in system config\n");
|
|
}
|
|
|
|
bootArgs->first_addr0 =
|
|
(int)bootArgs->configEnd + 1024;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|