
This replaces the memory map code for both pc and pc64 kernels with a unified implementation using the new portable memory map code. The main motivation is to be robust against broken e820 memory maps by the bios and delay the Conf.mem[] allocation after archinit(), so mp and acpi tables can be reserved and excluded from user memory. There are a few changes: new memreserve() function has been added for archinit() to reserve bios and acpi tables. upareserve() has been replaced by upaalloc(), which now has an address argument. umbrwmalloc() and umbmalloc() have been replaced by umballoc(). both upaalloc() and umballoc() return physical addresses or -1 on error. the physical address -1 is now used as a sentinel value instead of 0 when dealing with physical addresses. archmp and archacpi now always use vmap() to access the bios tables and reserve the ranges. more overflow checks have been added. ramscan() has been rewritten using vmap(). to handle the population of kernel memory, pc and pc64 now have pmap() and punmap() functions to do permanent mappings.
194 lines
3.7 KiB
C
194 lines
3.7 KiB
C
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
|
|
#define MAXCONF 64
|
|
static char *confname[MAXCONF];
|
|
static char *confval[MAXCONF];
|
|
static int nconf;
|
|
|
|
/* screen.c */
|
|
extern char* rgbmask2chan(char *buf, int depth, u32int rm, u32int gm, u32int bm);
|
|
|
|
/* vgavesa.c */
|
|
extern char* vesabootscreenconf(char*, char*, uchar*);
|
|
|
|
static void
|
|
multibootargs(void)
|
|
{
|
|
extern ulong multibootptr;
|
|
ulong *multiboot;
|
|
char *cp, *ep, *s;
|
|
ulong *m, l;
|
|
int i, n;
|
|
|
|
if(multibootptr == 0 || multibootptr >= MemMin)
|
|
return;
|
|
|
|
multiboot = (ulong*)KADDR(multibootptr);
|
|
|
|
cp = BOOTARGS;
|
|
ep = cp + BOOTARGSLEN-1;
|
|
|
|
/* memory map */
|
|
if((multiboot[0] & (1<<6)) != 0 && (l = multiboot[11]) >= 24){
|
|
cp = seprint(cp, ep, "*e820=");
|
|
m = KADDR(multiboot[12]);
|
|
while(m[0] >= 20 && m[0]+4 <= l){
|
|
uvlong base, size;
|
|
m++;
|
|
base = ((uvlong)m[0] | (uvlong)m[1]<<32);
|
|
size = ((uvlong)m[2] | (uvlong)m[3]<<32);
|
|
cp = seprint(cp, ep, "%.1lux %.16llux %.16llux ",
|
|
m[4] & 0xF, base, base+size);
|
|
l -= m[-1]+4;
|
|
m = (ulong*)((uintptr)m + m[-1]);
|
|
}
|
|
cp[-1] = '\n';
|
|
}
|
|
|
|
if((multiboot[0] & (1<<12)) != 0 && multiboot[22] != 0){ /* framebuffer */
|
|
uchar *p = (uchar*)multiboot + 112;
|
|
int depth = multiboot[27] & 0xFF;
|
|
char chan[32];
|
|
|
|
switch((multiboot[27]>>8) & 0xFF){
|
|
case 0:
|
|
snprint(chan, sizeof chan, "m%d", depth);
|
|
if(0){
|
|
case 1:
|
|
rgbmask2chan(chan, depth,
|
|
(1UL<<p[1])-1 << p[0],
|
|
(1UL<<p[3])-1 << p[2],
|
|
(1UL<<p[5])-1 << p[4]);
|
|
}
|
|
cp = seprint(cp, ep, "*bootscreen=%dx%dx%d %s %#lux\n",
|
|
(int)multiboot[24]*8 / depth,
|
|
(int)multiboot[26],
|
|
depth,
|
|
chan,
|
|
multiboot[22]);
|
|
}
|
|
} else
|
|
if((multiboot[0] & (1<<11)) != 0 && multiboot[19] != 0) /* vbe mode info */
|
|
cp = vesabootscreenconf(cp, ep, KADDR(multiboot[19]));
|
|
|
|
/* plan9.ini passed as the first module */
|
|
if((multiboot[0] & (1<<3)) != 0 && multiboot[5] > 0 && multiboot[6] != 0){
|
|
m = KADDR(multiboot[6]);
|
|
s = (char*)KADDR(m[0]);
|
|
if(m[1] > m[0]){
|
|
n = utfnlen(s, m[1] - m[0]);
|
|
if(n > 0)
|
|
cp = seprint(cp, ep, "%.*s\n", n, s);
|
|
}
|
|
}
|
|
|
|
/* command line */
|
|
if((multiboot[0] & (1<<2)) != 0 && multiboot[4] != 0){
|
|
n = tokenize(KADDR(multiboot[4]), confval, MAXCONF);
|
|
for(i=0; i<n; i++)
|
|
cp = seprint(cp, ep, "%s\n", confval[i]);
|
|
}
|
|
|
|
*cp = 0;
|
|
}
|
|
|
|
void
|
|
bootargsinit(void)
|
|
{
|
|
int i, j, n;
|
|
char *cp, *line[MAXCONF], *p, *q;
|
|
|
|
multibootargs();
|
|
|
|
/*
|
|
* parse configuration args from dos file plan9.ini
|
|
*/
|
|
cp = BOOTARGS; /* where b.com leaves its config */
|
|
cp[BOOTARGSLEN-1] = 0;
|
|
|
|
/*
|
|
* Strip out '\r', change '\t' -> ' '.
|
|
*/
|
|
p = cp;
|
|
for(q = cp; *q; q++){
|
|
if(*q == '\r')
|
|
continue;
|
|
if(*q == '\t')
|
|
*q = ' ';
|
|
*p++ = *q;
|
|
}
|
|
*p = 0;
|
|
|
|
n = getfields(cp, line, MAXCONF, 1, "\n");
|
|
for(i = 0; i < n; i++){
|
|
if(*line[i] == '#')
|
|
continue;
|
|
cp = strchr(line[i], '=');
|
|
if(cp == nil)
|
|
continue;
|
|
*cp++ = '\0';
|
|
for(j = 0; j < nconf; j++){
|
|
if(cistrcmp(confname[j], line[i]) == 0)
|
|
break;
|
|
}
|
|
confname[j] = line[i];
|
|
confval[j] = cp;
|
|
if(j == nconf)
|
|
nconf++;
|
|
}
|
|
}
|
|
|
|
char*
|
|
getconf(char *name)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < nconf; i++)
|
|
if(cistrcmp(confname[i], name) == 0)
|
|
return confval[i];
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
setconfenv(void)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < nconf; i++){
|
|
if(confname[i][0] != '*')
|
|
ksetenv(confname[i], confval[i], 0);
|
|
ksetenv(confname[i], confval[i], 1);
|
|
}
|
|
}
|
|
|
|
void
|
|
writeconf(void)
|
|
{
|
|
char *p, *q;
|
|
int n;
|
|
|
|
p = getconfenv();
|
|
if(waserror()) {
|
|
free(p);
|
|
nexterror();
|
|
}
|
|
|
|
/* convert to name=value\n format */
|
|
for(q=p; *q; q++) {
|
|
q += strlen(q);
|
|
*q = '=';
|
|
q += strlen(q);
|
|
*q = '\n';
|
|
}
|
|
n = q - p + 1;
|
|
if(n >= BOOTARGSLEN)
|
|
error("kernel configuration too large");
|
|
memmove(BOOTARGS, p, n);
|
|
memset(BOOTLINE, 0, BOOTLINELEN);
|
|
poperror();
|
|
free(p);
|
|
}
|