From 6498ce3bf29b5350975a0cd22bca8bcac19c4377 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 4 Apr 2020 15:47:50 +0200 Subject: [PATCH 1/6] ether8003: use physical addresses for ISAConfig ether->mem Fix the inconsistent use of ether->mem. Always use physical addresses. Let ether8390 convert to virtual addresses using KADDR() when we have to copy data in/out. --- sys/src/9/pc/ether8003.c | 13 ++++++------- sys/src/9/pc/ether8390.c | 16 ++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/sys/src/9/pc/ether8003.c b/sys/src/9/pc/ether8003.c index 871c26cad..c5df2df1b 100644 --- a/sys/src/9/pc/ether8003.c +++ b/sys/src/9/pc/ether8003.c @@ -88,7 +88,7 @@ reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8]) */ if(memcmp(&ea[1], &ic[1], 5) == 0){ memset(ic, 0, sizeof(ic)); - ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F; + ic[Msr] = (ether->mem>>13) & 0x3F; } else{ /* @@ -100,7 +100,7 @@ reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8]) inb(port+Msr); /* wiggle bus */ if(inb(port+Gp2) != 0xAA){ memset(ic, 0, sizeof(ic)); - ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F; + ic[Msr] = (ether->mem>>13) & 0x3F; } else ether->irq = irq8003[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)]; @@ -122,7 +122,7 @@ reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8]) ctlr->width = 1; } - ether->mem = (ulong)KADDR((ic[Msr] & 0x3F)<<13); + ether->mem = (ic[Msr] & 0x3F)<<13; if(ctlr->width == 2) ether->mem |= (ic[Laar] & 0x1F)<<19; else @@ -163,7 +163,7 @@ reset8216(Ether* ether, uchar[8]) irq = inb(port+0x0D); outb(port+Hcr, hcr); - ether->mem = (ulong)KADDR(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13)); + ether->mem = 0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13); ether->size = 8192*(1<<((addr>>4) & 0x03)); ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)]; @@ -262,9 +262,8 @@ reset(Ether* ether) } dp8390setea(ether); - if(umbrwmalloc(PADDR(ether->mem), ether->size, 0) == 0) - print("ether8003: warning - 0x%luX unavailable\n", - PADDR(ether->mem)); + if(umbrwmalloc(ether->mem, ether->size, 0) == 0) + print("ether8003: warning - 0x%luX unavailable\n", ether->mem); return 0; } diff --git a/sys/src/9/pc/ether8390.c b/sys/src/9/pc/ether8390.c index 16fa975f2..6853c5489 100644 --- a/sys/src/9/pc/ether8390.c +++ b/sys/src/9/pc/ether8390.c @@ -377,7 +377,7 @@ receive(Ether* ether) for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){ data = ctlr->nxtpkt*Dp8390BufSz; if(ctlr->ram) - memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr)); + memmove(&hdr, (uchar*)KADDR(ether->mem) + data, sizeof(Hdr)); else _dp8390read(ctlr, &hdr, data, sizeof(Hdr)); @@ -422,7 +422,7 @@ receive(Ether* ether) if((data+len) >= ctlr->pstop*Dp8390BufSz){ count = ctlr->pstop*Dp8390BufSz - data; if(ctlr->ram) - memmove(p, (void*)(ether->mem+data), count); + memmove(p, (uchar*)KADDR(ether->mem) + data, count); else _dp8390read(ctlr, p, data, count); p += count; @@ -431,7 +431,7 @@ receive(Ether* ether) } if(len){ if(ctlr->ram) - memmove(p, (void*)(ether->mem+data), len); + memmove(p, (uchar*)KADDR(ether->mem) + data, len); else _dp8390read(ctlr, p, data, len); } @@ -476,21 +476,13 @@ txstart(Ether* ether) return; /* - * Make sure the packet is of minimum length; * copy it to the card's memory by the appropriate means; * start the transmission. */ len = BLEN(bp); rp = bp->rp; - if(len < ETHERMINTU){ - rp = minpkt; - memmove(rp, bp->rp, len); - memset(rp+len, 0, ETHERMINTU-len); - len = ETHERMINTU; - } - if(ctlr->ram) - memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len); + memmove((uchar*)KADDR(ether->mem) + ctlr->tstart*Dp8390BufSz, rp, len); else dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len); freeb(bp); From 7451bb405d9e51965ce07d55f04f43dc45b6cef9 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 4 Apr 2020 15:55:48 +0200 Subject: [PATCH 2/6] ether8390: remove unused variables --- sys/src/9/pc/ether8390.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/src/9/pc/ether8390.c b/sys/src/9/pc/ether8390.c index 6853c5489..5f54bb459 100644 --- a/sys/src/9/pc/ether8390.c +++ b/sys/src/9/pc/ether8390.c @@ -461,7 +461,6 @@ txstart(Ether* ether) int len; Dp8390 *ctlr; Block *bp; - uchar minpkt[ETHERMINTU], *rp; ctlr = ether->ctlr; @@ -480,11 +479,10 @@ txstart(Ether* ether) * start the transmission. */ len = BLEN(bp); - rp = bp->rp; if(ctlr->ram) - memmove((uchar*)KADDR(ether->mem) + ctlr->tstart*Dp8390BufSz, rp, len); + memmove((uchar*)KADDR(ether->mem) + ctlr->tstart*Dp8390BufSz, bp->rp, len); else - dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len); + dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, bp->rp, len); freeb(bp); regw(ctlr, Tbcr0, len & 0xFF); From 8debb0736ea5578a195ab663bf9565d6e52ad83b Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 4 Apr 2020 16:04:27 +0200 Subject: [PATCH 3/6] kernel: add portable memory map code (port/memmap.c) This is a generic memory map for physical addresses. Entries can be added with memmapadd() giving a range and a type. Ranges can be allocated and freed from the map. The code automatically resolves overlapping ranges by type priority. --- sys/src/9/port/memmap.c | 271 +++++++++++++++++++++++++++++++++++++++ sys/src/9/port/portfns.h | 6 + 2 files changed, 277 insertions(+) create mode 100644 sys/src/9/port/memmap.c diff --git a/sys/src/9/port/memmap.c b/sys/src/9/port/memmap.c new file mode 100644 index 000000000..9a86b4e26 --- /dev/null +++ b/sys/src/9/port/memmap.c @@ -0,0 +1,271 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +enum { + Allocated = 1UL<<31, +}; + +typedef struct Mapent Mapent; +struct Mapent +{ + ulong type; + uvlong addr; + uvlong size; +}; + +static struct { + Lock; + int n; + int m; + Mapent a[256]; +} mapalloc; + +static void +dump1(Mapent *e) +{ + print("%.16llux-%.16llux %lux\n", e->addr, e->addr + e->size, e->type); +} + +static int +insert(uvlong addr, uvlong size, ulong type) +{ + Mapent *e; + + if(size == 0 || addr == -1 || addr + size-1 < addr) + return 0; + + if(mapalloc.n+mapalloc.m >= nelem(mapalloc.a)) + return 0; + + e = &mapalloc.a[mapalloc.n + mapalloc.m++]; + e->type = type; + e->addr = addr; + e->size = size; + + return 1; +} + +static Mapent* +lookup(uvlong addr) +{ + Mapent *i, *e; + + if(addr == -1) + return nil; + for(i = mapalloc.a, e = i + mapalloc.n; i < e; i++){ + if(i->addr > addr) + break; + if(addr - i->addr < i->size) + return i; + } + return nil; +} + +static int +compare(void *a, void *b) +{ + Mapent *ma = a, *mb = b; + + if(ma->addr < mb->addr) + return -1; + if(ma->addr > mb->addr) + return 1; + + if(ma->type < mb->type) + return -1; + if(ma->type > mb->type) + return 1; + + return 0; +} + +static void +sort(void) +{ + Mapent *d, *i, *j, *e; + +Again: + if(mapalloc.m == 0) + return; + mapalloc.n += mapalloc.m; + mapalloc.m = 0; + + qsort(mapalloc.a, mapalloc.n, sizeof(*e), compare); + + d = i = mapalloc.a; + e = i + mapalloc.n; + while(i < e){ + if(i->size == 0) + goto Skip; + for(j = i+1; j < e; j++){ + if(j->size == 0) + continue; + if(j->addr - i->addr >= i->size) + break; + if(j->type <= i->type){ + if(j->addr - i->addr + j->size <= i->size) + j->size = 0; + else { + j->size -= i->addr + i->size - j->addr; + j->addr = i->addr + i->size; + } + continue; + } + if(j->addr - i->addr + j->size < i->size) + if(!insert(j->addr + j->size, i->size - (j->addr + j->size - i->addr), i->type)) + continue; + i->size = j->addr - i->addr; + if(i->size == 0) + goto Skip; + } + if(d > mapalloc.a){ + j = d-1; + if(i->addr - j->addr == j->size && i->type == j->type){ + j->size += i->size; + i->size = 0; + goto Skip; + } + } + memmove(d, i, sizeof(*i)); + d++; + Skip: + i++; + } + if(mapalloc.m > 0) + memmove(d, e, mapalloc.m*sizeof(*e)); + mapalloc.n = d - mapalloc.a; + goto Again; +} + +void +memmapdump(void) +{ + int i; + + lock(&mapalloc); + sort(); + for(i = 0; i < mapalloc.n; i++) + dump1(&mapalloc.a[i]); + unlock(&mapalloc); +} + +uvlong +memmapnext(uvlong addr, ulong type) +{ + Mapent *i, *e; + + lock(&mapalloc); + sort(); + for(i = mapalloc.a, e = i+mapalloc.n; i < e; i++){ + if(((i->type ^ type) & ~Allocated) == 0 + && (addr == -1 || i->addr > addr)){ + addr = i->addr; + unlock(&mapalloc); + return addr; + } + } + unlock(&mapalloc); + return -1; +} + +uvlong +memmapsize(uvlong addr, uvlong align) +{ + Mapent *i; + uvlong size; + + size = 0; + lock(&mapalloc); + sort(); + if((i = lookup(addr)) != nil){ + if(align){ + addr += align-1; + addr &= ~(align-1); + } + if(addr - i->addr < i->size) + size = i->size - (addr - i->addr); + } + unlock(&mapalloc); + return size; +} + +void +memmapadd(uvlong addr, uvlong size, ulong type) +{ + type &= ~Allocated; + lock(&mapalloc); + if(insert(addr, size, type)) + if(mapalloc.n+mapalloc.m >= nelem(mapalloc.a)-1) + sort(); + unlock(&mapalloc); +} + +uvlong +memmapalloc(uvlong addr, uvlong size, uvlong align, ulong type) +{ + Mapent *i, *e; + + type &= ~Allocated; + lock(&mapalloc); + sort(); + if(addr != -1){ + i = lookup(addr); + if(i == nil || i->type != type) + goto Fail; + if(align){ + addr += align-1; + addr &= ~(align-1); + if(addr - i->addr >= i->size) + goto Fail; + } + if(addr - i->addr + size > i->size) + goto Fail; +Alloc: + if(size > 0 && !insert(addr, size, type|Allocated)) + goto Fail; + unlock(&mapalloc); + return addr; + } + e = mapalloc.a + mapalloc.n; + for(i = mapalloc.a; i < e; i++){ + if(i->type != type) + continue; + addr = i->addr; + if(align){ + addr += align-1; + addr &= ~(align-1); + if(addr - i->addr >= i->size) + continue; + } + if(addr - i->addr + size <= i->size) + goto Alloc; + } +Fail: + unlock(&mapalloc); + return -1; +} + +void +memmapfree(uvlong addr, uvlong size, ulong type) +{ + Mapent *i; + + lock(&mapalloc); + sort(); + i = lookup(addr); + if(i == nil + || i->type != (type|Allocated) + || addr - i->addr + size > i->size){ + unlock(&mapalloc); + return; + } + if(i->addr < addr) + insert(i->addr, addr - i->addr, i->type); + if(addr - i->addr + size < i->size) + insert(addr+size, addr - i->addr + i->size - size, i->type); + i->type &= ~Allocated; + unlock(&mapalloc); +} diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 7197afe87..87ae97d6b 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -168,6 +168,12 @@ void* malloc(ulong); void* mallocalign(ulong, ulong, long, ulong); void mallocsummary(void); Block* mem2bl(uchar*, int); +void memmapdump(void); +uvlong memmapnext(uvlong, ulong); +uvlong memmapsize(uvlong, uvlong); +void memmapadd(uvlong, uvlong, ulong); +uvlong memmapalloc(uvlong, uvlong, uvlong, ulong); +void memmapfree(uvlong, uvlong, ulong); ulong mcountseg(Segment*); void mfreeseg(Segment*, uintptr, ulong); void microdelay(int); From 5f1b70f437ed4f598f9439e201f1f7644f5ce7b5 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 4 Apr 2020 16:48:37 +0200 Subject: [PATCH 4/6] pc, pc64: new memory map code 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. --- sys/src/9/pc/archacpi.c | 28 +- sys/src/9/pc/archmp.c | 26 +- sys/src/9/pc/bootargs.c | 2 +- sys/src/9/pc/devi82365.c | 8 +- sys/src/9/pc/devpccard.c | 48 +- sys/src/9/pc/ether8003.c | 2 +- sys/src/9/pc/fns.h | 17 +- sys/src/9/pc/main.c | 3 +- sys/src/9/pc/mem.h | 2 +- sys/src/9/pc/memory.c | 1279 ++++++++++++-------------------------- sys/src/9/pc/mkfile | 1 + sys/src/9/pc/mmu.c | 16 +- sys/src/9/pc/pci.c | 2 +- sys/src/9/pc/screen.c | 13 +- sys/src/9/pc64/fns.h | 17 +- sys/src/9/pc64/main.c | 3 +- sys/src/9/pc64/mem.h | 2 +- sys/src/9/pc64/memory.c | 802 ------------------------ sys/src/9/pc64/mkfile | 1 + sys/src/9/pc64/mmu.c | 35 +- 20 files changed, 530 insertions(+), 1777 deletions(-) delete mode 100644 sys/src/9/pc64/memory.c diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c index 793a83b79..3c020b84f 100644 --- a/sys/src/9/pc/archacpi.c +++ b/sys/src/9/pc/archacpi.c @@ -113,8 +113,9 @@ maptable(uvlong xpa) int i; pa = xpa; - if((uvlong)pa != xpa || pa == 0) + if((uvlong)pa != xpa || pa == 0 || pa+7 < pa) return; + if(ntblpa >= nelem(tblpa) || ntblmap >= nelem(tblmap)) return; @@ -124,21 +125,18 @@ maptable(uvlong xpa) } tblpa[ntblpa++] = pa; + memreserve(pa, 8); if((t = vmap(pa, 8)) == nil) return; l = get32(t->len); - if(l < Tblsz){ - vunmap(t, 8); - return; - } - if(memcheck(pa, l) != l){ - print("maptable: ignoring %.4s at [%#p-%#p); overlaps usable memory\n", - (char*)t->sig, pa, pa+l); + if(l < Tblsz + || l >= 0x10000000 + || pa+l-1 < pa){ vunmap(t, 8); return; } + memreserve(pa, l); vunmap(t, 8); - if((t = vmap(pa, l)) == nil) return; if(checksum(t, l)){ @@ -177,9 +175,10 @@ maptables(void) return; if(!checksum(rsd, 20)) maptable(get32(rsd->raddr)); - if(rsd->rev >= 2) + if(rsd->rev >= 2){ if(!checksum(rsd, 36)) maptable(get64(rsd->xaddr)); + } } static Apic* @@ -567,8 +566,6 @@ acpiinit(void) ulong lapicbase; int machno, i, c; - maptables(); - amlinit(); /* load DSDT */ @@ -789,14 +786,15 @@ identify(void) pa = (uintptr)strtoull(cp, nil, 16); if(pa <= 1) rsd = rsdsearch(); - else if(pa < MemMin) - rsd = KADDR(pa); - else + else { + memreserve(pa, sizeof(Rsd)); rsd = vmap(pa, sizeof(Rsd)); + } if(rsd == nil) return 1; if(checksum(rsd, 20) && checksum(rsd, 36)) return 1; + maptables(); addarchfile("acpitbls", 0444, readtbls, nil); addarchfile("acpimem", 0600, readmem, writemem); if(strcmp(cp, "0") == 0) diff --git a/sys/src/9/pc/archmp.c b/sys/src/9/pc/archmp.c index fec5f7638..edf256256 100644 --- a/sys/src/9/pc/archmp.c +++ b/sys/src/9/pc/archmp.c @@ -383,7 +383,7 @@ identify(void) { char *cp; _MP_ *_mp_; - ulong len; + ulong pa, len; if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0) return 1; @@ -399,26 +399,28 @@ identify(void) return 1; len = PCMPsz; - if(_mp_->physaddr < MemMin) - pcmp = KADDR(_mp_->physaddr); - else if((pcmp = vmap(_mp_->physaddr, len)) == nil) + pa = _mp_->physaddr; + if(pa + len-1 < pa) return 1; - if(pcmp->length < len + + memreserve(pa, len); + if((pcmp = vmap(pa, len)) == nil) + return 1; + if(pcmp->length < PCMPsz + || pa + pcmp->length-1 < pa || memcmp(pcmp, "PCMP", 4) != 0 || (pcmp->version != 1 && pcmp->version != 4)){ Bad: - if((uintptr)pcmp < KZERO) - vunmap(pcmp, len); + vunmap(pcmp, len); pcmp = nil; return 1; } len = pcmp->length; - if((uintptr)pcmp < KZERO) - vunmap(pcmp, PCMPsz); - if(_mp_->physaddr < MemMin) - pcmp = KADDR(_mp_->physaddr); - else if((pcmp = vmap(_mp_->physaddr, len)) == nil) + memreserve(pa, len); + vunmap(pcmp, PCMPsz); + if((pcmp = vmap(pa, len)) == nil) return 1; + if(checksum(pcmp, len) != 0) goto Bad; diff --git a/sys/src/9/pc/bootargs.c b/sys/src/9/pc/bootargs.c index a971515d2..f6627e222 100644 --- a/sys/src/9/pc/bootargs.c +++ b/sys/src/9/pc/bootargs.c @@ -24,7 +24,7 @@ multibootargs(void) ulong *m, l; int i, n; - if(multibootptr == 0) + if(multibootptr == 0 || multibootptr >= MemMin) return; multiboot = (ulong*)KADDR(multibootptr); diff --git a/sys/src/9/pc/devi82365.c b/sys/src/9/pc/devi82365.c index 6defcaeb9..20cace973 100644 --- a/sys/src/9/pc/devi82365.c +++ b/sys/src/9/pc/devi82365.c @@ -268,7 +268,6 @@ pcmmap(int slotno, ulong offset, int len, int attr) if((we & bit)) if(m->attr == attr) if(offset >= m->ca && e <= m->cea){ - m->ref++; unlock(&pp->mlock); return m; @@ -285,12 +284,13 @@ pcmmap(int slotno, ulong offset, int len, int attr) /* if isa space isn't big enough, free it and get more */ if(m->len < len){ - if(m->isa){ + if(m->len){ umbfree(m->isa, m->len); m->len = 0; } - m->isa = PADDR(umbmalloc(0, len, Mgran)); - if(m->isa == 0){ + m->isa = umballoc(-1, len, Mgran); + if(m->isa == -1){ + m->isa = 0; print("pcmmap: out of isa space\n"); unlock(&pp->mlock); return 0; diff --git a/sys/src/9/pc/devpccard.c b/sys/src/9/pc/devpccard.c index 5f884c63d..7559af0ad 100644 --- a/sys/src/9/pc/devpccard.c +++ b/sys/src/9/pc/devpccard.c @@ -521,7 +521,6 @@ devpccardlink(void) int i; uchar intl; char *p; - void *baddrva; if (initialized) return; @@ -543,7 +542,6 @@ devpccardlink(void) while ((pci = pcimatch(pci, 0, 0)) != nil) { ulong baddr; Cardbus *cb; - int slot; uchar pin; if(pci->ccrb != 6 || pci->ccru != 7) @@ -555,8 +553,7 @@ devpccardlink(void) continue; /* initialize this slot */ - slot = nslots++; - cb = &cbslots[slot]; + cb = &cbslots[nslots]; cb->pci = pci; cb->variant = &variant[i]; @@ -635,27 +632,30 @@ devpccardlink(void) pcicfgw8(cb->pci, 0xD4, 0xCA); } - if (intl != 0xff && intl != pci->intl) - intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus"); - intl = pci->intl; - if ((baddr = pcicfgr32(cb->pci, PciBAR0)) == 0) { int size = (pci->did == Ricoh_478_did)? 0x10000: 0x1000; - - baddr = upaalloc(size, size); - baddrva = vmap(baddr, size); + baddr = upaalloc(-1, size, size); + if(baddr == -1) + continue; pcicfgw32(cb->pci, PciBAR0, baddr); - cb->regs = (ulong *)baddrva; + cb->regs = (ulong *)vmap(baddr, size); } else cb->regs = (ulong *)vmap(baddr, 4096); + if(cb->regs == nil) + continue; cb->state = SlotEmpty; + if (intl != 0xff && intl != pci->intl) + intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus"); + /* Don't really know what to do with this... */ i82365probe(cb, LegacyAddr, LegacyAddr + 1); print("#Y%ld: %s, %.8ulX intl %d\n", cb - cbslots, variant[i].name, baddr, pci->intl); + + nslots++; } if (nslots == 0){ @@ -815,16 +815,22 @@ configure(Cardbus *cb) if(iolen < 512) iolen = 512; iobase = ioreserve(~0, iolen, 0, "cardbus"); - pcicfgw32(cb->pci, PciCBIBR0, iobase); - pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1); - pcicfgw32(cb->pci, PciCBIBR1, 0); - pcicfgw32(cb->pci, PciCBILR1, 0); + if(iobase == -1) + return; rombase = memlen; memlen += romlen; if(memlen < 1*1024*1024) memlen = 1*1024*1024; - membase = upaalloc(memlen, 4*1024*1024); /* TO DO: better alignment */ + membase = upaalloc(-1, memlen, 4*1024*1024); /* TO DO: better alignment */ + if(membase == -1) + return; + + pcicfgw32(cb->pci, PciCBIBR0, iobase); + pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1); + pcicfgw32(cb->pci, PciCBIBR1, 0); + pcicfgw32(cb->pci, PciCBILR1, 0); + pcicfgw32(cb->pci, PciCBMBR0, membase); pcicfgw32(cb->pci, PciCBMLR0, membase + memlen-1); pcicfgw32(cb->pci, PciCBMBR1, 0); @@ -1451,7 +1457,6 @@ isamap(Cardbus *cb, ulong offset, int len, int attr) if((we & bit)) if(m->attr == attr) if(offset >= m->ca && e <= m->cea){ - m->ref++; return m; } @@ -1465,12 +1470,13 @@ isamap(Cardbus *cb, ulong offset, int len, int attr) /* if isa space isn't big enough, free it and get more */ if(m->len < len){ - if(m->isa){ + if(m->len){ umbfree(m->isa, m->len); m->len = 0; } - m->isa = PADDR(umbmalloc(0, len, Mgran)); - if(m->isa == 0){ + m->isa = umballoc(-1, len, Mgran); + if(m->isa == -1){ + m->isa = 0; print("isamap: out of isa space\n"); return 0; } diff --git a/sys/src/9/pc/ether8003.c b/sys/src/9/pc/ether8003.c index c5df2df1b..13ee44893 100644 --- a/sys/src/9/pc/ether8003.c +++ b/sys/src/9/pc/ether8003.c @@ -262,7 +262,7 @@ reset(Ether* ether) } dp8390setea(ether); - if(umbrwmalloc(ether->mem, ether->size, 0) == 0) + if(umballoc(ether->mem, ether->size, 0) == -1) print("ether8003: warning - 0x%luX unavailable\n", ether->mem); return 0; diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index 8e4326730..fc82116fb 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -105,7 +105,8 @@ void mathinit(void); void mb386(void); void mb586(void); void meminit(void); -void memorysummary(void); +void meminit0(void); +void memreserve(uintptr, uintptr); void mfence(void); #define mmuflushtlb(pdb) putcr3(pdb) void mmuinit(void); @@ -158,7 +159,8 @@ int (*_pcmspecial)(char *, ISAConf *); void pcmspecialclose(int); void (*_pcmspecialclose)(int); void pcmunmap(int, PCMmap*); -int pdbmap(ulong*, ulong, ulong, int); +void pmap(ulong, ulong, int); +void punmap(ulong, int); void procrestore(Proc*); void procsave(Proc*); void procsetup(Proc*); @@ -188,13 +190,10 @@ void trapinit(void); void trapinit0(void); int tas(void*); uvlong tscticks(uvlong*); -ulong umbmalloc(ulong, int, int); -void umbfree(ulong, int); -ulong umbrwmalloc(ulong, int, int); -void umbrwfree(ulong, int); -ulong upaalloc(int, int); -void upafree(ulong, int); -void upareserve(ulong, int); +ulong umballoc(ulong, ulong, ulong); +void umbfree(ulong, ulong); +ulong upaalloc(ulong, ulong, ulong); +void upafree(ulong, ulong); void vectortable(void); void* vmap(ulong, int); int vmapsync(ulong); diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c index b8486ef78..01fa783ad 100644 --- a/sys/src/9/pc/main.c +++ b/sys/src/9/pc/main.c @@ -34,11 +34,12 @@ main(void) trapinit0(); i8253init(); cpuidentify(); + meminit0(); + archinit(); meminit(); ramdiskinit(); confinit(); xinit(); - archinit(); bootscreeninit(); if(i8237alloc != nil) i8237alloc(); diff --git a/sys/src/9/pc/mem.h b/sys/src/9/pc/mem.h index 417430a90..56649e305 100644 --- a/sys/src/9/pc/mem.h +++ b/sys/src/9/pc/mem.h @@ -54,7 +54,7 @@ #define USTKSIZE (16*1024*1024) /* size of user stack */ /* - * Fundamental addresses - bottom 64kB saved for return to real mode + * Fundamental addresses */ #define CONFADDR (KZERO+0x1200) /* info passed from boot loader */ #define APBOOTSTRAP (KZERO+0x7000) /* AP bootstrap code (overlaps CONFADDR) */ diff --git a/sys/src/9/pc/memory.c b/sys/src/9/pc/memory.c index 1c6d04190..9b3968f59 100644 --- a/sys/src/9/pc/memory.c +++ b/sys/src/9/pc/memory.c @@ -1,10 +1,3 @@ -/* - * Size memory and create the kernel page-tables on the fly while doing so. - * Called from main(), this code should only be run by the bootstrap processor. - * - * MemMin is what the bootstrap code in l.s has already mapped; - * MemMax is the limit of physical memory to scan. - */ #include "u.h" #include "../port/lib.h" #include "mem.h" @@ -13,316 +6,150 @@ #include "io.h" #include "ureg.h" -#define MEMDEBUG 0 - -u32int MemMin = 8*MB; /* set in l.s */ - enum { - MemUPA = 0, /* unbacked physical address */ - MemRAM = 1, /* physical memory */ - MemUMB = 2, /* upper memory block (<16MB) */ - MemACPI = 3, /* ACPI tables */ - MemReserved = 4, - NMemType = 5, + MemUPA = 0, /* unbacked physical address */ + MemUMB = 1, /* upper memory block (<16MB) */ + MemRAM = 2, /* physical memory */ + MemACPI = 3, /* ACPI tables */ + MemReserved = 4, /* don't allocate */ - KB = 1024, - - MemMax = (3*1024+768)*MB, + KB = 1024, }; -typedef struct Map Map; -struct Map { - ulong size; - ulong addr; -}; +u32int MemMin; /* set by l.s */ -typedef struct RMap RMap; -struct RMap { - char* name; - Map* map; - Map* mapend; - - Lock; -}; - -/* - * Memory allocation tracking. - */ -static Map mapupa[16]; -static RMap rmapupa = { - "unallocated unbacked physical memory", - mapupa, - &mapupa[nelem(mapupa)-1], -}; - -static Map mapram[16]; -static RMap rmapram = { - "physical memory", - mapram, - &mapram[nelem(mapram)-1], -}; - -static Map mapumb[64]; -static RMap rmapumb = { - "upper memory block", - mapumb, - &mapumb[nelem(mapumb)-1], -}; - -static Map mapumbrw[16]; -static RMap rmapumbrw = { - "UMB device memory", - mapumbrw, - &mapumbrw[nelem(mapumbrw)-1], -}; - -static Map mapacpi[16]; -static RMap rmapacpi = { - "ACPI tables", - mapacpi, - &mapacpi[nelem(mapacpi)-1], -}; - -void -mapprint(RMap *rmap) -{ - Map *mp; - - print("%s\n", rmap->name); - for(mp = rmap->map; mp->size; mp++) - print("\t%8.8luX %8.8luX (%lud)\n", mp->addr, mp->addr+mp->size, mp->size); -} - - -void -memdebug(void) -{ - ulong maxpa, maxpa1, maxpa2; - - maxpa = (nvramread(0x18)<<8)|nvramread(0x17); - maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30); - maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15); - print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n", - maxpa, MB+maxpa*KB, maxpa1, maxpa2); - - mapprint(&rmapram); - mapprint(&rmapumb); - mapprint(&rmapumbrw); - mapprint(&rmapupa); - mapprint(&rmapacpi); -} - -static void -mapfree(RMap* rmap, ulong addr, ulong size) -{ - Map *mp; - ulong t; - - if(size <= 0) - return; - - lock(rmap); - for(mp = rmap->map; mp->addr <= addr && mp->size; mp++) - ; - - if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){ - (mp-1)->size += size; - if(addr+size == mp->addr){ - (mp-1)->size += mp->size; - while(mp->size){ - mp++; - (mp-1)->addr = mp->addr; - (mp-1)->size = mp->size; - } - } - } - else{ - if(addr+size == mp->addr && mp->size){ - mp->addr -= size; - mp->size += size; - } - else do{ - if(mp >= rmap->mapend){ - print("mapfree: %s: losing 0x%luX, %ld\n", - rmap->name, addr, size); - break; - } - t = mp->addr; - mp->addr = addr; - addr = t; - t = mp->size; - mp->size = size; - mp++; - }while(size = t); - } - unlock(rmap); -} - -static ulong -mapalloc(RMap* rmap, ulong addr, int size, int align) -{ - Map *mp; - ulong maddr, oaddr; - - lock(rmap); - for(mp = rmap->map; mp->size; mp++){ - maddr = mp->addr; - - if(addr){ - /* - * A specific address range has been given: - * if the current map entry is greater then - * the address is not in the map; - * if the current map entry does not overlap - * the beginning of the requested range then - * continue on to the next map entry; - * if the current map entry does not entirely - * contain the requested range then the range - * is not in the map. - */ - if(maddr > addr) - break; - if(mp->size < addr - maddr) /* maddr+mp->size < addr, but no overflow */ - continue; - if(addr - maddr > mp->size - size) /* addr+size > maddr+mp->size, but no overflow */ - break; - maddr = addr; - } - - if(align > 0) - maddr = ((maddr+align-1)/align)*align; - if(mp->addr+mp->size-maddr < size) - continue; - - oaddr = mp->addr; - mp->addr = maddr+size; - mp->size -= maddr-oaddr+size; - if(mp->size == 0){ - do{ - mp++; - (mp-1)->addr = mp->addr; - }while((mp-1)->size = mp->size); - } - - unlock(rmap); - if(oaddr != maddr) - mapfree(rmap, oaddr, maddr-oaddr); - - return maddr; - } - unlock(rmap); - - return 0; -} - -/* - * Allocate from the ram map directly to make page tables. - * Called by mmuwalk during e820scan. - */ void* rampage(void) { - ulong m; + uintptr pa; if(conf.mem[0].npage != 0) return xspanalloc(BY2PG, BY2PG, 0); - m = mapalloc(&rmapram, 0, BY2PG, BY2PG); - if(m == 0) - return nil; - return KADDR(m); + + /* + * Allocate from the map directly to make page tables. + */ + pa = memmapalloc(-1, BY2PG, BY2PG, MemRAM); + if(pa == -1 || cankaddr(pa) == 0) + panic("rampage: out of memory\n"); + return KADDR(pa); } static void -umbexclude(void) +mapkzero(uintptr base, uintptr len, int type) { - int size; - ulong addr; - char *op, *p, *rptr; + uintptr flags, n; - if((p = getconf("umbexclude")) == nil) - return; - - while(p && *p != '\0' && *p != '\n'){ - op = p; - addr = strtoul(p, &rptr, 0); - if(rptr == nil || rptr == p || *rptr != '-'){ - print("umbexclude: invalid argument <%s>\n", op); - break; - } - p = rptr+1; - - size = strtoul(p, &rptr, 0) - addr + 1; - if(size <= 0){ - print("umbexclude: bad range <%s>\n", op); - break; - } - if(rptr != nil && *rptr == ',') - *rptr++ = '\0'; - p = rptr; - - mapalloc(&rmapumb, addr, size, 0); + if(base < MemMin && base+len > MemMin){ + mapkzero(base, MemMin-base, type); + len = base+len-MemMin; + base = MemMin; } + + n = cankaddr(base); + if(n == 0) + return; + if(len > n) + len = n; + + switch(type){ + default: + return; + case MemRAM: + if(base < MemMin) + return; + flags = PTEWRITE|PTEVALID; + break; + case MemUMB: + if(base < MemMin) + punmap(base+KZERO, len); + flags = PTEWRITE|PTEUNCACHED|PTEVALID; + break; + } +#ifdef PTENOEXEC + flags |= PTENOEXEC; +#endif + pmap(base|flags, base+KZERO, len); +} + +static uintptr +ebdaseg(void) +{ + uchar *bda; + + if(memcmp(KADDR(0xfffd9), "EISA", 4) != 0) + return 0; + bda = KADDR(0x400); + return ((bda[0x0f]<<8)|bda[0x0e]) << 4; +} + +static uintptr +convmemsize(void) +{ + uintptr top; + uchar *bda; + + bda = KADDR(0x400); + top = ((bda[0x14]<<8) | bda[0x13])*KB; + + if(top < 64*KB || top > 640*KB) + top = 640*KB; /* sanity */ + + /* Reserved for BIOS tables */ + top -= 1*KB; + + return top; } static void -umbscan(void) +lowraminit(void) { + uintptr base, pa, len; uchar *p; /* - * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces - * which aren't used; they can be used later for devices which - * want to allocate some virtual address space. - * Check for two things: - * 1) device BIOS ROM. This should start with a two-byte header - * of 0x55 0xAA, followed by a byte giving the size of the ROM - * in 512-byte chunks. These ROM's must start on a 2KB boundary. - * 2) device memory. This is read-write. - * There are some assumptions: there's VGA memory at 0xA0000 and - * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature - * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up - * for grabs; check anyway. + * Discover the memory bank information for conventional memory + * (i.e. less than 640KB). The base is the first location after the + * bootstrap processor MMU information and the limit is obtained from + * the BIOS data area. */ - p = KADDR(0xD0000); - while(p < (uchar*)KADDR(0xE0000)){ - /* - * Test for 0x55 0xAA before poking obtrusively, - * some machines (e.g. Thinkpad X20) seem to map - * something dynamic here (cardbus?) causing weird - * problems if it is changed. - */ + base = PADDR(CPU0END); + pa = convmemsize(); + if(base < pa) + memmapadd(base, pa-base, MemRAM); + + /* Reserve BIOS tables */ + memmapadd(pa, 1*KB, MemReserved); + + /* Reserve EBDA */ + if((pa = ebdaseg()) != 0) + memmapadd(pa, 1*KB, MemReserved); + memmapadd(0xA0000-1*KB, 1*KB, MemReserved); + + /* Reserve the VGA frame buffer */ + umballoc(0xA0000, 128*KB, 0); + + /* Reserve VGA ROM */ + memmapadd(0xC0000, 64*KB, MemReserved); + + /* + * Scan the Upper Memory Blocks (0xD0000->0xF0000) for device BIOS ROMs. + * This should start with a two-byte header of 0x55 0xAA, followed by a + * byte giving the size of the ROM in 512-byte chunks. + * These ROM's must start on a 2KB boundary. + */ + for(p = (uchar*)KADDR(0xD0000); p < (uchar*)KADDR(0xF0000); p += len){ + len = 2*KB; if(p[0] == 0x55 && p[1] == 0xAA){ - p += p[2]*512; - continue; + if(p[2] != 0) + len = p[2]*512; + memmapadd(PADDR(p), len, MemReserved); + len = ROUND(len, 2*KB); } - - p[0] = 0xCC; - p[2*KB-1] = 0xCC; - if(p[0] != 0xCC || p[2*KB-1] != 0xCC){ - p[0] = 0x55; - p[1] = 0xAA; - p[2] = 4; - if(p[0] == 0x55 && p[1] == 0xAA){ - p += p[2]*512; - continue; - } - if(p[0] == 0xFF && p[1] == 0xFF) - mapfree(&rmapumb, PADDR(p), 2*KB); - } - else - mapfree(&rmapumbrw, PADDR(p), 2*KB); - p += 2*KB; } - p = KADDR(0xE0000); - if(p[0] != 0x55 || p[1] != 0xAA){ - p[0] = 0xCC; - p[64*KB-1] = 0xCC; - if(p[0] != 0xCC && p[64*KB-1] != 0xCC) - mapfree(&rmapumb, PADDR(p), 64*KB); - } - - umbexclude(); + /* Reserve BIOS ROM */ + memmapadd(0xF0000, 64*KB, MemReserved); } int @@ -355,29 +182,10 @@ sigscan(uchar *addr, int len, char *sig, int size, int step) return nil; } -static uintptr -convmemsize(void) -{ - uintptr top; - uchar *bda; - - bda = KADDR(0x400); - top = ((bda[0x14]<<8) | bda[0x13])*KB; - - if(top < 64*KB || top > 640*KB) - top = 640*KB; /* sanity */ - - /* reserved for bios tables (EBDA) */ - top -= 1*KB; - - return top; -} - void* sigsearch(char* signature, int size) { uintptr p; - uchar *bda; void *r; /* @@ -388,587 +196,48 @@ sigsearch(char* signature, int size) * 3) within the BIOS ROM address space between 0xf0000 and 0xfffff * (but will actually check 0xe0000 to 0xfffff). */ - bda = KADDR(0x400); - if(memcmp(KADDR(0xfffd9), "EISA", 4) == 0){ - if((p = (bda[0x0f]<<8)|bda[0x0e]) != 0){ - if((r = sigscan(KADDR(p<<4), 1024, signature, size, 16)) != nil) - return r; - } + if((p = ebdaseg()) != 0){ + if((r = sigscan(KADDR(p), 1*KB, signature, size, 16)) != nil) + return r; } - if((r = sigscan(KADDR(convmemsize()), 1024, signature, size, 16)) != nil) + if((r = sigscan(KADDR(convmemsize()), 1*KB, signature, size, 16)) != nil) return r; /* hack for virtualbox: look in KiB below 0xa0000 */ - if((r = sigscan(KADDR(0xa0000-1024), 1024, signature, size, 16)) != nil) + if((r = sigscan(KADDR(0xA0000-1*KB), 1*KB, signature, size, 16)) != nil) return r; - return sigscan(KADDR(0xe0000), 0x20000, signature, size, 16); + return sigscan(KADDR(0xE0000), 128*KB, signature, size, 16); } void* rsdsearch(void) { static char signature[] = "RSD PTR "; + uintptr base, size; uchar *v, *p; - Map *m; if((p = sigsearch(signature, 36)) != nil) return p; if((p = sigsearch(signature, 20)) != nil) return p; - for(m = rmapacpi.map; m < rmapacpi.mapend && m->size; m++){ - if(m->size > 0x7FFFFFFF) + + for(base = memmapnext(-1, MemACPI); base != -1; base = memmapnext(base, MemACPI)){ + size = memmapsize(base, 0); + if(size == 0 || size > 0x7fffffff) continue; - if((v = vmap(m->addr, m->size)) != nil){ - p = sigscan(v, m->size, signature, 36, 4); + if((v = vmap(base, size)) != nil){ + p = sigscan(v, size, signature, 36, 4); if(p == nil) - p = sigscan(v, m->size, signature, 20, 4); - vunmap(v, m->size); + p = sigscan(v, size, signature, 20, 4); + vunmap(v, size); if(p != nil) - return vmap(m->addr + (p - v), 64); + return vmap(base + (p - v), 64); } } return nil; } -static void -lowraminit(void) -{ - uintptr pa, x; - - /* - * Initialise the memory bank information for conventional memory - * (i.e. less than 640KB). The base is the first location after the - * bootstrap processor MMU information and the limit is obtained from - * the BIOS data area. - */ - x = PADDR(CPU0END); - pa = convmemsize(); - if(x < pa){ - mapfree(&rmapram, x, pa-x); - memset(KADDR(x), 0, pa-x); /* keep us honest */ - } - - x = PADDR(PGROUND((uintptr)end)); - pa = MemMin; - if(x > pa) - panic("kernel too big"); - mapfree(&rmapram, x, pa-x); - memset(KADDR(x), 0, pa-x); /* keep us honest */ -} - -static void -ramscan(ulong maxmem) -{ - ulong *k0, kzero, map, maxkpa, maxpa, pa, *pte, *table, *va, vbase, x; - int nvalid[NMemType]; - - /* - * The bootstrap code has has created a prototype page - * table which maps the first MemMin of physical memory to KZERO. - * The page directory is at m->pdb and the first page of - * free memory is after the per-processor MMU information. - */ - pa = MemMin; - - /* - * Check if the extended memory size can be obtained from the CMOS. - * If it's 0 then it's either not known or >= 64MB. Always check - * at least 24MB in case there's a memory gap (up to 8MB) below 16MB; - * in this case the memory from the gap is remapped to the top of - * memory. - * The value in CMOS is supposed to be the number of KB above 1MB. - */ - if(maxmem == 0){ - x = (nvramread(0x18)<<8)|nvramread(0x17); - if(x == 0 || x >= (63*KB)) - maxpa = MemMax; - else - maxpa = MB+x*KB; - if(maxpa < 24*MB) - maxpa = 24*MB; - }else - maxpa = maxmem; - maxkpa = (u32int)-KZERO; /* 2^32 - KZERO */ - - /* - * March up memory from MemMin to maxpa 1MB at a time, - * mapping the first page and checking the page can - * be written and read correctly. The page tables are created here - * on the fly, allocating from low memory as necessary. - */ - k0 = (ulong*)KADDR(0); - kzero = *k0; - map = 0; - x = 0x12345678; - memset(nvalid, 0, sizeof(nvalid)); - - /* - * Can't map memory to KADDR(pa) when we're walking because - * can only use KADDR for relatively low addresses. - * Instead, map each 4MB we scan to the virtual address range - * MemMin->MemMin+4MB while we are scanning. - */ - vbase = MemMin; - while(pa < maxpa){ - /* - * Map the page. Use mapalloc(&rmapram, ...) to make - * the page table if necessary, it will be returned to the - * pool later if it isn't needed. Map in a fixed range (the second 4M) - * because high physical addresses cannot be passed to KADDR. - */ - va = (void*)(vbase + pa%(4*MB)); - table = &m->pdb[PDX(va)]; - if(pa%(4*MB) == 0){ - if(map == 0 && (map = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0) - break; - memset(KADDR(map), 0, BY2PG); - *table = map|PTEWRITE|PTEVALID; - memset(nvalid, 0, sizeof(nvalid)); - } - table = KADDR(PPN(*table)); - pte = &table[PTX(va)]; - - *pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID; - mmuflushtlb(PADDR(m->pdb)); - /* - * Write a pattern to the page and write a different - * pattern to a possible mirror at KZERO. If the data - * reads back correctly the chunk is some type of RAM (possibly - * a linearly-mapped VGA framebuffer, for instance...) and - * can be cleared and added to the memory pool. If not, the - * chunk is marked uncached and added to the UMB pool if <16MB - * or is marked invalid and added to the UPA pool. - */ - *va = x; - *k0 = ~x; - if(*va == x){ - nvalid[MemRAM] += MB/BY2PG; - mapfree(&rmapram, pa, MB); - - do{ - *pte++ = pa|PTEWRITE|PTEVALID; - pa += BY2PG; - }while(pa % MB); - mmuflushtlb(PADDR(m->pdb)); - /* memset(va, 0, MB); so damn slow to memset all of memory */ - } - else if(pa < 16*MB){ - nvalid[MemUMB] += MB/BY2PG; - mapfree(&rmapumb, pa, MB); - - do{ - *pte++ = pa|PTEWRITE|PTEUNCACHED|PTEVALID; - pa += BY2PG; - }while(pa % MB); - } - else{ - nvalid[MemUPA] += MB/BY2PG; - mapfree(&rmapupa, pa, MB); - - *pte = 0; - pa += MB; - } - /* - * Done with this 4MB chunk, review the options: - * 1) not physical memory and >=16MB - invalidate the PDB entry; - * 2) physical memory - use the 4MB page extension if possible; - * 3) not physical memory and <16MB - use the 4MB page extension - * if possible; - * 4) mixed or no 4MB page extension - commit the already - * initialised space for the page table. - */ - if(pa%(4*MB) == 0 && pa >= 32*MB && nvalid[MemUPA] == (4*MB)/BY2PG){ - /* - * If we encounter a 4MB chunk of missing memory - * at a sufficiently high offset, call it the end of - * memory. Otherwise we run the risk of thinking - * that video memory is real RAM. - */ - break; - } - if(pa <= maxkpa && pa%(4*MB) == 0){ - table = &m->pdb[PDX(KADDR(pa - 4*MB))]; - if(nvalid[MemUPA] == (4*MB)/BY2PG) - *table = 0; - else if(nvalid[MemRAM] == (4*MB)/BY2PG && (m->cpuiddx & Pse)) - *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEVALID; - else if(nvalid[MemUMB] == (4*MB)/BY2PG && (m->cpuiddx & Pse)) - *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID; - else{ - *table = map|PTEWRITE|PTEVALID; - map = 0; - } - } - mmuflushtlb(PADDR(m->pdb)); - x += 0x3141526; - } - /* - * If we didn't reach the end of the 4MB chunk, that part won't - * be mapped. Commit the already initialised space for the page table. - */ - if(pa % (4*MB) && pa <= maxkpa){ - m->pdb[PDX(KADDR(pa))] = map|PTEWRITE|PTEVALID; - map = 0; - } - if(map) - mapfree(&rmapram, map, BY2PG); - - m->pdb[PDX(vbase)] = 0; - mmuflushtlb(PADDR(m->pdb)); - - mapfree(&rmapupa, pa, (u32int)-pa); - *k0 = kzero; -} - -static void -map(ulong base, ulong len, int type) -{ - ulong e, n; - ulong *table, flags, maxkpa; - - /* - * Split any call crossing MemMin to make below simpler. - */ - if(base < MemMin && len > MemMin-base){ - n = MemMin - base; - map(base, n, type); - map(MemMin, len-n, type); - } - - /* - * Let lowraminit and umbscan hash out the low MemMin. - */ - if(base < MemMin) - return; - - /* - * Any non-memory below 16*MB is used as upper mem blocks. - */ - if(type == MemUPA && base < 16*MB && len > 16*MB-base){ - map(base, 16*MB-base, MemUMB); - map(16*MB, len-(16*MB-base), MemUPA); - return; - } - - /* - * Memory below CPU0END is reserved for the kernel - * and already mapped. - */ - if(base < PADDR(CPU0END)){ - n = PADDR(CPU0END) - base; - if(len <= n) - return; - map(PADDR(CPU0END), len-n, type); - return; - } - - /* - * Memory between KTZERO and end is the kernel itself - * and is already mapped. - */ - if(base < PADDR(KTZERO) && len > PADDR(KTZERO)-base){ - map(base, PADDR(KTZERO)-base, type); - return; - } - if(PADDR(KTZERO) < base && base < PADDR(PGROUND((ulong)end))){ - n = PADDR(PGROUND((ulong)end)); - if(len <= n) - return; - map(PADDR(PGROUND((ulong)end)), len-n, type); - return; - } - - /* - * Now we have a simple case. - */ - // print("map %.8lux %.8lux %d\n", base, base+len, type); - switch(type){ - case MemRAM: - mapfree(&rmapram, base, len); - flags = PTEWRITE|PTEVALID; - break; - case MemUMB: - mapfree(&rmapumb, base, len); - flags = PTEWRITE|PTEUNCACHED|PTEVALID; - break; - case MemUPA: - mapfree(&rmapupa, base, len); - flags = 0; - break; - case MemACPI: - mapfree(&rmapacpi, base, len); - flags = 0; - break; - default: - case MemReserved: - flags = 0; - break; - } - - /* - * bottom MemMin is already mapped - just twiddle flags. - * (not currently used - see above) - */ - if(base < MemMin){ - table = KADDR(PPN(m->pdb[PDX(base)])); - e = base+len; - base = PPN(base); - for(; base= maxkpa) - return; - if(len > maxkpa-base) - len = maxkpa - base; - pdbmap(m->pdb, base|flags, base+KZERO, len); - } -} - -typedef struct Emap Emap; -struct Emap -{ - int type; - uvlong base; - uvlong top; -}; -static Emap emap[128]; -static int nemap; - -static int -emapcmp(const void *va, const void *vb) -{ - Emap *a, *b; - - a = (Emap*)va; - b = (Emap*)vb; - if(a->top < b->top) - return -1; - if(a->top > b->top) - return 1; - if(a->base < b->base) - return -1; - if(a->base > b->base) - return 1; - return 0; -} - -static void -e820clean(void) -{ - Emap *e; - int i, j; - - qsort(emap, nemap, sizeof emap[0], emapcmp); - for(i=j=0; ibase >= (1ULL<<32)) - break; - - /* merge adjacent entries of the same type */ - if(i+1 < nemap && e[0].top == e[1].base && e[0].type == e[1].type){ - e[1].base = e[0].base; - continue; - } - - memmove(&emap[j++], e, sizeof *e); - } - nemap = j; -} - -static int -e820scan(void) -{ - ulong base, len, last; - Emap *e; - char *s; - int i; - - /* passed by bootloader */ - if((s = getconf("*e820")) == nil) - if((s = getconf("e820")) == nil) - return -1; - nemap = 0; - while(nemap < nelem(emap)){ - while(*s == ' ') - s++; - if(*s == 0) - break; - e = emap + nemap; - e->type = 1; - if(s[1] == ' '){ /* new format */ - e->type = s[0] - '0'; - s += 2; - } - e->base = strtoull(s, &s, 16); - if(*s != ' ') - break; - e->top = strtoull(s, &s, 16); - if(*s != ' ' && *s != 0) - break; - if(e->base >= e->top) - continue; - if(++nemap == nelem(emap)) - e820clean(); - } - e820clean(); - if(nemap == 0) - return -1; - last = 0; - for(i=0; itop <= last) - continue; - if(e->base < last) - base = last; - else - base = e->base; - if(e->top > (1ULL<<32)) - len = -base; - else - len = e->top - base; - /* - * If the map skips addresses, mark them available. - */ - if(last < base) - map(last, base-last, MemUPA); - - switch(e->type){ - case 1: - map(base, len, MemRAM); - break; - case 3: - map(base, len, MemACPI); - break; - default: - map(base, len, MemReserved); - } - - last = base + len; - if(last == 0) - break; - } - if(last != 0) - map(last, -last, MemUPA); - return 0; -} - -void -meminit(void) -{ - int i; - Map *mp; - Confmem *cm; - ulong pa, *pte; - ulong maxmem, lost; - char *p; - - if(p = getconf("*maxmem")) - maxmem = strtoul(p, 0, 0); - else - maxmem = 0; - - /* - * Set special attributes for memory between 640KB and 1MB: - * VGA memory is writethrough; - * BIOS ROM's/UMB's are uncached; - * then scan for useful memory. - */ - for(pa = 0xA0000; pa < 0xC0000; pa += BY2PG){ - pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0); - *pte |= PTEWT; - } - for(pa = 0xC0000; pa < 0x100000; pa += BY2PG){ - pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0); - *pte |= PTEUNCACHED; - } - mmuflushtlb(PADDR(m->pdb)); - - umbscan(); - lowraminit(); - if(e820scan() < 0) - ramscan(maxmem); - - /* - * Set the conf entries describing banks of allocatable memory. - */ - for(i=0; ibase = mp->addr; - cm->npage = mp->size/BY2PG; - } - - lost = 0; - for(; i\n", op); + break; + } + p = rptr+1; + + size = strtoul(p, &rptr, 0) - pa + 1; + if(size <= 0){ + print("umbexclude: bad range <%s>\n", op); + break; + } + if(rptr != nil && *rptr == ',') + *rptr++ = '\0'; + p = rptr; + + memmapalloc(pa, size, 0, MemUMB); } - return a; } -void -upafree(ulong pa, int size) +static int +e820scan(void) { - mapfree(&rmapupa, pa, size); + uvlong base, top, size; + int type; + char *s; + + /* passed by bootloader */ + if((s = getconf("*e820")) == nil) + if((s = getconf("e820")) == nil) + return -1; + + for(;;){ + while(*s == ' ') + s++; + if(*s == 0) + break; + type = 1; + if(s[1] == ' '){ /* new format */ + type = s[0] - '0'; + s += 2; + } + base = strtoull(s, &s, 16); + if(*s != ' ') + break; + top = strtoull(s, &s, 16); + if(*s != ' ' && *s != 0) + break; + if(base >= top) + continue; + switch(type){ + case 1: + memmapadd(base, top - base, MemRAM); + break; + case 3: + memmapadd(base, top - base, MemACPI); + break; + default: + memmapadd(base, top - base, MemReserved); + } + } + + for(base = memmapnext(-1, MemRAM); base != -1; base = memmapnext(base, MemRAM)){ + size = memmapsize(base, BY2PG) & ~(BY2PG-1); + if(size != 0) + mapkzero(PGROUND(base), size, MemRAM); + } + + return 0; } -void -upareserve(ulong pa, int size) +static void +ramscan(uintptr pa, uintptr top, uintptr chunk) { - ulong a; - - a = mapalloc(&rmapupa, pa, size, 0); - if(a != pa){ + ulong save, pat, seed, *v, *k0; + int i, n, w; + + pa += chunk-1; + pa &= ~(chunk-1); + top &= ~(chunk-1); + + n = chunk/sizeof(*v); + w = BY2PG/sizeof(*v); + + k0 = KADDR(0); + save = *k0; + + pat = 0x12345678UL; + for(; pa < top; pa += chunk){ + /* write pattern */ + seed = pat; + if((v = vmap(pa, chunk)) == nil) + continue; + for(i = 0; i < n; i += w){ + pat += 0x3141526UL; + v[i] = pat; + *k0 = ~pat; + if(v[i] != pat) + goto Bad; + } + vunmap(v, chunk); + + /* verify pattern */ + pat = seed; + if((v = vmap(pa, chunk)) == nil) + continue; + for(i = 0; i < n; i += w){ + pat += 0x3141526UL; + if(v[i] != pat) + goto Bad; + } + vunmap(v, chunk); + + memmapadd(pa, chunk, MemRAM); + mapkzero(pa, chunk, MemRAM); + continue; + + Bad: + vunmap(v, chunk); + + if(pa+chunk <= 16*MB) + memmapadd(pa, chunk, MemUMB); + /* - * This can happen when we're using the E820 - * map, which might have already reserved some - * of the regions claimed by the pci devices. + * If we encounter a chunk of missing memory + * at a sufficiently high offset, call it the end of + * memory. Otherwise we run the risk of thinking + * that video memory is real RAM. */ - // print("upareserve: cannot reserve pa=%#.8lux size=%d\n", pa, size); - if(a != 0) - mapfree(&rmapupa, a, size); + if(pa >= 32*MB) + break; } + + *k0 = save; } +/* + * Sort out initial memory map and discover RAM. + */ void -memorysummary(void) +meminit0(void) { - memdebug(); + /* + * Add the already mapped memory after the kernel. + */ + if(MemMin < PADDR(PGROUND((uintptr)end))) + panic("kernel too big"); + memmapadd(PADDR(PGROUND((uintptr)end)), MemMin-PADDR(PGROUND((uintptr)end)), MemRAM); + + /* + * Memory between KTZERO and end is the kernel itself. + */ + memreserve(PADDR(KTZERO), PADDR(PGROUND((uintptr)end))-PADDR(KTZERO)); + + /* + * Memory below CPU0END is reserved for the kernel. + */ + memreserve(0, PADDR(CPU0END)); + + /* + * Addresses below 16MB default to be upper + * memory blocks usable for ISA devices. + */ + memmapadd(0, 16*MB, MemUMB); + + /* + * Everything between 16MB and 4GB defaults + * to unbacked physical addresses usable for + * device mappings. + */ + memmapadd(16*MB, (u32int)-16*MB, MemUPA); + + /* + * On 386, reserve >= 4G as we have no PAE support. + */ + if(sizeof(void*) == 4) + memmapadd((u32int)-BY2PG, -((uvlong)((u32int)-BY2PG)), MemReserved); + + /* + * Discover conventional RAM, ROMs and UMBs. + */ + lowraminit(); + + /* + * Discover more RAM and map to KZERO. + */ + if(e820scan() < 0) + ramscan(MemMin, -((uintptr)MemMin), 4*MB); } +/* + * Until the memory map is finalized by meminit(), + * archinit() should reserve memory of discovered BIOS + * and ACPI tables by calling memreserve() to prevent + * them from getting allocated and trashed. + * This is due to the UEFI and BIOS memory map being + * unreliable and sometimes marking these ranges as RAM. + */ +void +memreserve(uintptr pa, uintptr size) +{ + assert(conf.mem[0].npage == 0); + + size += (pa & BY2PG-1); + size &= ~(BY2PG-1); + pa &= ~(BY2PG-1); + memmapadd(pa, size, MemReserved); +} + +/* + * Finalize the memory map: + * (re-)map the upper memory blocks + * allocate all usable ram to the conf.mem[] banks + */ +void +meminit(void) +{ + uintptr base, size; + Confmem *cm; + + umbexclude(); + for(base = memmapnext(-1, MemUMB); base != -1; base = memmapnext(base, MemUMB)){ + size = memmapsize(base, BY2PG) & ~(BY2PG-1); + if(size != 0) + mapkzero(PGROUND(base), size, MemUMB); + } + + cm = &conf.mem[0]; + for(base = memmapnext(-1, MemRAM); base != -1; base = memmapnext(base, MemRAM)){ + size = memmapsize(base, BY2PG) & ~(BY2PG-1); + if(size == 0) + continue; + cm->base = memmapalloc(base, size, BY2PG, MemRAM); + if(cm->base == -1) + continue; + base = cm->base; + cm->npage = size/BY2PG; + if(++cm >= &conf.mem[nelem(conf.mem)]) + break; + } + + if(0) memmapdump(); +} diff --git a/sys/src/9/pc/mkfile b/sys/src/9/pc/mkfile index 0d8f19efe..2c3f6e395 100644 --- a/sys/src/9/pc/mkfile +++ b/sys/src/9/pc/mkfile @@ -35,6 +35,7 @@ PORT=\ random.$O\ rdb.$O\ rebootcmd.$O\ + memmap.$O\ segment.$O\ syscallfmt.$O\ sysfile.$O\ diff --git a/sys/src/9/pc/mmu.c b/sys/src/9/pc/mmu.c index c9ff28abb..edcf866db 100644 --- a/sys/src/9/pc/mmu.c +++ b/sys/src/9/pc/mmu.c @@ -544,6 +544,7 @@ static Lock vmaplock; static int findhole(ulong *a, int n, int count); static ulong vmapalloc(ulong size); +static int pdbmap(ulong *, ulong, ulong, int); static void pdbunmap(ulong*, ulong, int); /* @@ -679,7 +680,7 @@ vunmap(void *v, int size) /* * Add kernel mappings for pa -> va for a section of size bytes. */ -int +static int pdbmap(ulong *pdb, ulong pa, ulong va, int size) { int pse; @@ -749,6 +750,19 @@ pdbunmap(ulong *pdb, ulong va, int size) } } +void +pmap(ulong pa, ulong va, int size) +{ + pdbmap(MACHP(0)->pdb, pa, va, size); +} + +void +punmap(ulong va, int size) +{ + pdbunmap(MACHP(0)->pdb, va, size); + mmuflushtlb(PADDR(m->pdb)); +} + /* * Handle a fault by bringing vmap up to date. * Only copy pdb entries and they never go away, diff --git a/sys/src/9/pc/pci.c b/sys/src/9/pc/pci.c index 18f4edaa5..2b55fea69 100644 --- a/sys/src/9/pc/pci.c +++ b/sys/src/9/pc/pci.c @@ -1084,7 +1084,7 @@ pcireservemem(void) for(p=pciroot; p; p=p->list) for(i=0; imem); i++) if((p->mem[i].bar&~4) != 0 && (p->mem[i].bar&1) == 0) - upareserve(p->mem[i].bar&~0x0F, p->mem[i].size); + upaalloc(p->mem[i].bar&~0x0F, p->mem[i].size, 0); } static int diff --git a/sys/src/9/pc/screen.c b/sys/src/9/pc/screen.c index 8bfec7f3c..b3a9f5cc9 100644 --- a/sys/src/9/pc/screen.c +++ b/sys/src/9/pc/screen.c @@ -94,6 +94,7 @@ int screenaperture(int size, int align) { VGAscr *scr; + ulong pa; scr = &vgascreen[0]; @@ -113,10 +114,11 @@ screenaperture(int size, int align) * The driver will tell the card to use it. */ size = PGROUND(size); - scr->paddr = upaalloc(size, align); - if(scr->paddr == 0) + pa = upaalloc(-1, size, align); + if(pa == -1) return -1; - scr->vaddr = vmap(scr->paddr, size); + scr->paddr = pa; + scr->vaddr = vmap(pa, size); if(scr->vaddr == nil) return -1; scr->apsize = size; @@ -482,8 +484,8 @@ vgalinearaddr0(VGAscr *scr, ulong paddr, int size) if(nsize > 64*MB) nsize = 64*MB; scr->vaddr = vmap(npaddr, nsize); - if(scr->vaddr == 0) - return "cannot allocate vga frame buffer"; + if(scr->vaddr == nil) + return "cannot map vga frame buffer"; patwc(scr->vaddr, nsize); @@ -576,6 +578,7 @@ bootmapfb(VGAscr *scr, ulong pa, ulong sz) } } } + upaalloc(pa, sz, 0); return vgalinearaddr0(scr, pa, sz); } diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h index f4da48240..1fb982c64 100644 --- a/sys/src/9/pc64/fns.h +++ b/sys/src/9/pc64/fns.h @@ -103,7 +103,8 @@ void mathinit(void); void mb386(void); void mb586(void); void meminit(void); -void memorysummary(void); +void meminit0(void); +void memreserve(uintptr, uintptr); void mfence(void); #define mmuflushtlb() putcr3(getcr3()) void mmuinit(void); @@ -157,7 +158,8 @@ int (*_pcmspecial)(char *, ISAConf *); void pcmspecialclose(int); void (*_pcmspecialclose)(int); void pcmunmap(int, PCMmap*); -void pmap(uintptr *, uintptr, uintptr, vlong); +void pmap(uintptr, uintptr, vlong); +void punmap(uintptr, vlong); void preallocpages(void); void procrestore(Proc*); void procsave(Proc*); @@ -187,13 +189,10 @@ void trapinit(void); void trapinit0(void); int tas(void*); uvlong tscticks(uvlong*); -uintptr umbmalloc(uintptr, int, int); -void umbfree(uintptr, int); -uintptr umbrwmalloc(uintptr, int, int); -void umbrwfree(uintptr, int); -uintptr upaalloc(int, int); -void upafree(uintptr, int); -void upareserve(uintptr, int); +ulong umballoc(ulong, ulong, ulong); +void umbfree(ulong, ulong); +ulong upaalloc(ulong, ulong, ulong); +void upafree(ulong, ulong); void vectortable(void); void vmxprocrestore(Proc *); void vmxshutdown(void); diff --git a/sys/src/9/pc64/main.c b/sys/src/9/pc64/main.c index 3e11f6eed..83f770587 100644 --- a/sys/src/9/pc64/main.c +++ b/sys/src/9/pc64/main.c @@ -184,11 +184,12 @@ main(void) trapinit0(); i8253init(); cpuidentify(); + meminit0(); + archinit(); meminit(); ramdiskinit(); confinit(); xinit(); - archinit(); bootscreeninit(); if(i8237alloc != nil) i8237alloc(); diff --git a/sys/src/9/pc64/mem.h b/sys/src/9/pc64/mem.h index d9bc638f1..3a9bf9a1a 100644 --- a/sys/src/9/pc64/mem.h +++ b/sys/src/9/pc64/mem.h @@ -60,7 +60,7 @@ #define KMAPSIZE (2*MiB) /* - * Fundamental addresses - bottom 64kB saved for return to real mode + * Fundamental addresses */ #define CONFADDR (KZERO+0x1200ull) /* info passed from boot loader */ #define APBOOTSTRAP (KZERO+0x7000ull) /* AP bootstrap code */ diff --git a/sys/src/9/pc64/memory.c b/sys/src/9/pc64/memory.c deleted file mode 100644 index 6a00dd3a6..000000000 --- a/sys/src/9/pc64/memory.c +++ /dev/null @@ -1,802 +0,0 @@ -/* - * Size memory and create the kernel page-tables on the fly while doing so. - * Called from main(), this code should only be run by the bootstrap processor. - * - * MemMin is what the bootstrap code in l.s has already mapped; - */ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "ureg.h" - -u32int MemMin; /* set by l.s */ - -#define MEMDEBUG 0 - -enum { - MemUPA = 0, /* unbacked physical address */ - MemRAM = 1, /* physical memory */ - MemUMB = 2, /* upper memory block (<16MB) */ - MemACPI = 3, /* ACPI tables */ - MemReserved = 4, - NMemType = 5, - - KB = 1024, -}; - -typedef struct Map Map; -struct Map { - uintptr size; - uintptr addr; -}; - -typedef struct RMap RMap; -struct RMap { - char* name; - Map* map; - Map* mapend; - - Lock; -}; - -/* - * Memory allocation tracking. - */ -static Map mapupa[64]; -static RMap rmapupa = { - "unallocated unbacked physical memory", - mapupa, - &mapupa[nelem(mapupa)-1], -}; - -static Map mapram[16]; -static RMap rmapram = { - "physical memory", - mapram, - &mapram[nelem(mapram)-1], -}; - -static Map mapumb[64]; -static RMap rmapumb = { - "upper memory block", - mapumb, - &mapumb[nelem(mapumb)-1], -}; - -static Map mapumbrw[16]; -static RMap rmapumbrw = { - "UMB device memory", - mapumbrw, - &mapumbrw[nelem(mapumbrw)-1], -}; - -static Map mapacpi[16]; -static RMap rmapacpi = { - "ACPI tables", - mapacpi, - &mapacpi[nelem(mapacpi)-1], -}; - -void -mapprint(RMap *rmap) -{ - Map *mp; - - print("%s\n", rmap->name); - for(mp = rmap->map; mp->size; mp++) - print("\t%#p %#p (%#p)\n", mp->addr, mp->addr+mp->size, mp->size); -} - - -void -memdebug(void) -{ - ulong maxpa, maxpa1, maxpa2; - - maxpa = (nvramread(0x18)<<8)|nvramread(0x17); - maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30); - maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15); - print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n", - maxpa, MB+maxpa*KB, maxpa1, maxpa2); - - mapprint(&rmapram); - mapprint(&rmapumb); - mapprint(&rmapumbrw); - mapprint(&rmapupa); - mapprint(&rmapacpi); -} - -static void -mapfree(RMap* rmap, uintptr addr, uintptr size) -{ - Map *mp; - uintptr t; - - if(size <= 0) - return; - - lock(rmap); - for(mp = rmap->map; mp->addr <= addr && mp->size; mp++) - ; - - if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){ - (mp-1)->size += size; - if(addr+size == mp->addr){ - (mp-1)->size += mp->size; - while(mp->size){ - mp++; - (mp-1)->addr = mp->addr; - (mp-1)->size = mp->size; - } - } - } - else{ - if(addr+size == mp->addr && mp->size){ - mp->addr -= size; - mp->size += size; - } - else do{ - if(mp >= rmap->mapend){ - print("mapfree: %s: losing %#p, %#p\n", - rmap->name, addr, size); - break; - } - t = mp->addr; - mp->addr = addr; - addr = t; - t = mp->size; - mp->size = size; - mp++; - }while(size = t); - } - unlock(rmap); -} - -static uintptr -mapalloc(RMap* rmap, uintptr addr, int size, int align) -{ - Map *mp; - uintptr maddr, oaddr; - - lock(rmap); - for(mp = rmap->map; mp->size; mp++){ - maddr = mp->addr; - - if(addr){ - /* - * A specific address range has been given: - * if the current map entry is greater then - * the address is not in the map; - * if the current map entry does not overlap - * the beginning of the requested range then - * continue on to the next map entry; - * if the current map entry does not entirely - * contain the requested range then the range - * is not in the map. - */ - if(maddr > addr) - break; - if(mp->size < addr - maddr) /* maddr+mp->size < addr, but no overflow */ - continue; - if(addr - maddr > mp->size - size) /* addr+size > maddr+mp->size, but no overflow */ - break; - maddr = addr; - } - - if(align > 0) - maddr = ((maddr+align-1)/align)*align; - if(mp->addr+mp->size-maddr < size) - continue; - - oaddr = mp->addr; - mp->addr = maddr+size; - mp->size -= maddr-oaddr+size; - if(mp->size == 0){ - do{ - mp++; - (mp-1)->addr = mp->addr; - }while((mp-1)->size = mp->size); - } - - unlock(rmap); - if(oaddr != maddr) - mapfree(rmap, oaddr, maddr-oaddr); - - return maddr; - } - unlock(rmap); - - return 0; -} - -/* - * Allocate from the ram map directly to make page tables. - * Called by mmuwalk during e820scan. - */ -void* -rampage(void) -{ - uintptr m; - - if(conf.mem[0].npage != 0) - return xspanalloc(BY2PG, BY2PG, 0); - m = mapalloc(&rmapram, 0, BY2PG, BY2PG); - if(m == 0) - return nil; - return KADDR(m); -} - -static void -umbexclude(void) -{ - int size; - ulong addr; - char *op, *p, *rptr; - - if((p = getconf("umbexclude")) == nil) - return; - - while(p && *p != '\0' && *p != '\n'){ - op = p; - addr = strtoul(p, &rptr, 0); - if(rptr == nil || rptr == p || *rptr != '-'){ - print("umbexclude: invalid argument <%s>\n", op); - break; - } - p = rptr+1; - - size = strtoul(p, &rptr, 0) - addr + 1; - if(size <= 0){ - print("umbexclude: bad range <%s>\n", op); - break; - } - if(rptr != nil && *rptr == ',') - *rptr++ = '\0'; - p = rptr; - - mapalloc(&rmapumb, addr, size, 0); - } -} - -static void -umbscan(void) -{ - uchar *p; - - /* - * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces - * which aren't used; they can be used later for devices which - * want to allocate some virtual address space. - * Check for two things: - * 1) device BIOS ROM. This should start with a two-byte header - * of 0x55 0xAA, followed by a byte giving the size of the ROM - * in 512-byte chunks. These ROM's must start on a 2KB boundary. - * 2) device memory. This is read-write. - * There are some assumptions: there's VGA memory at 0xA0000 and - * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature - * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up - * for grabs; check anyway. - */ - p = KADDR(0xD0000); - while(p < (uchar*)KADDR(0xE0000)){ - /* - * Test for 0x55 0xAA before poking obtrusively, - * some machines (e.g. Thinkpad X20) seem to map - * something dynamic here (cardbus?) causing weird - * problems if it is changed. - */ - if(p[0] == 0x55 && p[1] == 0xAA){ - p += p[2]*512; - continue; - } - - p[0] = 0xCC; - p[2*KB-1] = 0xCC; - if(p[0] != 0xCC || p[2*KB-1] != 0xCC){ - p[0] = 0x55; - p[1] = 0xAA; - p[2] = 4; - if(p[0] == 0x55 && p[1] == 0xAA){ - p += p[2]*512; - continue; - } - if(p[0] == 0xFF && p[1] == 0xFF) - mapfree(&rmapumb, PADDR(p), 2*KB); - } - else - mapfree(&rmapumbrw, PADDR(p), 2*KB); - p += 2*KB; - } - - p = KADDR(0xE0000); - if(p[0] != 0x55 || p[1] != 0xAA){ - p[0] = 0xCC; - p[64*KB-1] = 0xCC; - if(p[0] != 0xCC && p[64*KB-1] != 0xCC) - mapfree(&rmapumb, PADDR(p), 64*KB); - } - - umbexclude(); -} - -int -checksum(void *v, int n) -{ - uchar *p, s; - - s = 0; - p = v; - while(n-- > 0) - s += *p++; - return s; -} - -static void* -sigscan(uchar *addr, int len, char *sig, int size, int step) -{ - uchar *e, *p; - int sl; - - sl = strlen(sig); - e = addr+len-(size > sl ? size : sl); - for(p = addr; p <= e; p += step){ - if(memcmp(p, sig, sl) != 0) - continue; - if(size && checksum(p, size) != 0) - continue; - return p; - } - return nil; -} - -static uintptr -convmemsize(void) -{ - uintptr top; - uchar *bda; - - bda = KADDR(0x400); - top = ((bda[0x14]<<8) | bda[0x13])*KB; - - if(top < 64*KB || top > 640*KB) - top = 640*KB; /* sanity */ - - /* reserved for bios tables (EBDA) */ - top -= 1*KB; - - return top; -} - -void* -sigsearch(char* signature, int size) -{ - uintptr p; - uchar *bda; - void *r; - - /* - * Search for the data structure: - * 1) within the first KiB of the Extended BIOS Data Area (EBDA), or - * 2) within the last KiB of system base memory if the EBDA segment - * is undefined, or - * 3) within the BIOS ROM address space between 0xf0000 and 0xfffff - * (but will actually check 0xe0000 to 0xfffff). - */ - bda = KADDR(0x400); - if(memcmp(KADDR(0xfffd9), "EISA", 4) == 0){ - if((p = (bda[0x0f]<<8)|bda[0x0e]) != 0){ - if((r = sigscan(KADDR(p<<4), 1024, signature, size, 16)) != nil) - return r; - } - } - if((r = sigscan(KADDR(convmemsize()), 1024, signature, size, 16)) != nil) - return r; - - /* hack for virtualbox: look in KiB below 0xa0000 */ - if((r = sigscan(KADDR(0xa0000-1024), 1024, signature, size, 16)) != nil) - return r; - - return sigscan(KADDR(0xe0000), 0x20000, signature, size, 16); -} - -void* -rsdsearch(void) -{ - static char signature[] = "RSD PTR "; - uchar *v, *p; - Map *m; - - if((p = sigsearch(signature, 36)) != nil) - return p; - if((p = sigsearch(signature, 20)) != nil) - return p; - for(m = rmapacpi.map; m < rmapacpi.mapend && m->size; m++){ - if(m->size > 0x7FFFFFFF) - continue; - if((v = vmap(m->addr, m->size)) != nil){ - p = sigscan(v, m->size, signature, 36, 4); - if(p == nil) - p = sigscan(v, m->size, signature, 20, 4); - vunmap(v, m->size); - if(p != nil) - return vmap(m->addr + (p - v), 64); - } - } - return nil; -} - -static void -lowraminit(void) -{ - uintptr pa, x; - - /* - * Initialise the memory bank information for conventional memory - * (i.e. less than 640KB). The base is the first location after the - * bootstrap processor MMU information and the limit is obtained from - * the BIOS data area. - */ - x = PADDR(CPU0END); - pa = convmemsize(); - if(x < pa){ - mapfree(&rmapram, x, pa-x); - memset(KADDR(x), 0, pa-x); /* keep us honest */ - } - - x = PADDR(PGROUND((uintptr)end)); - pa = MemMin; - if(x > pa) - panic("kernel too big"); - mapfree(&rmapram, x, pa-x); - memset(KADDR(x), 0, pa-x); /* keep us honest */ -} - -static void -map(uintptr base, uintptr len, int type) -{ - uintptr n, flags, maxkpa; - - /* - * Split any call crossing MemMin to make below simpler. - */ - if(base < MemMin && len > MemMin-base){ - n = MemMin - base; - map(base, n, type); - map(MemMin, len-n, type); - } - - /* - * Let umbscan hash out the low MemMin. - */ - if(base < MemMin) - return; - - /* - * Any non-memory below 16*MB is used as upper mem blocks. - */ - if(type == MemUPA && base < 16*MB && len > 16*MB-base){ - map(base, 16*MB-base, MemUMB); - map(16*MB, len-(16*MB-base), MemUPA); - return; - } - - /* - * Memory below CPU0END is reserved for the kernel - * and already mapped. - */ - if(base < PADDR(CPU0END)){ - n = PADDR(CPU0END) - base; - if(len <= n) - return; - map(PADDR(CPU0END), len-n, type); - return; - } - - /* - * Memory between KTZERO and end is the kernel itself - * and is already mapped. - */ - if(base < PADDR(KTZERO) && len > PADDR(KTZERO)-base){ - map(base, PADDR(KTZERO)-base, type); - return; - } - if(PADDR(KTZERO) < base && base < PADDR(PGROUND((uintptr)end))){ - n = PADDR(PGROUND((uintptr)end)); - if(len <= n) - return; - map(PADDR(PGROUND((uintptr)end)), len-n, type); - return; - } - - /* - * Now we have a simple case. - */ - switch(type){ - case MemRAM: - mapfree(&rmapram, base, len); - flags = PTEWRITE|PTENOEXEC|PTEVALID; - break; - case MemUMB: - mapfree(&rmapumb, base, len); - flags = PTEWRITE|PTEUNCACHED|PTENOEXEC|PTEVALID; - break; - case MemUPA: - mapfree(&rmapupa, base, len); - flags = 0; - break; - case MemACPI: - mapfree(&rmapacpi, base, len); - flags = 0; - break; - case MemReserved: - default: - flags = 0; - break; - } - - if(flags){ - maxkpa = -KZERO; - if(base >= maxkpa) - return; - if(len > maxkpa-base) - len = maxkpa - base; - pmap(m->pml4, base|flags, base+KZERO, len); - } -} - -typedef struct Emap Emap; -struct Emap -{ - int type; - uvlong base; - uvlong top; -}; -static Emap emap[128]; -static int nemap; - -static int -emapcmp(const void *va, const void *vb) -{ - Emap *a, *b; - - a = (Emap*)va; - b = (Emap*)vb; - if(a->top < b->top) - return -1; - if(a->top > b->top) - return 1; - if(a->base < b->base) - return -1; - if(a->base > b->base) - return 1; - return 0; -} - -static void -e820clean(void) -{ - Emap *e; - int i, j; - - qsort(emap, nemap, sizeof emap[0], emapcmp); - for(i=j=0; itype = 1; - if(s[1] == ' '){ /* new format */ - e->type = s[0] - '0'; - s += 2; - } - e->base = strtoull(s, &s, 16); - if(*s != ' ') - break; - e->top = strtoull(s, &s, 16); - if(*s != ' ' && *s != 0) - break; - if(e->base >= e->top) - continue; - if(++nemap == nelem(emap)) - e820clean(); - } - e820clean(); - if(nemap == 0) - return -1; - last = 0; - for(i=0; itop <= last) - continue; - if(e->base < last) - base = last; - else - base = e->base; - len = e->top - base; - /* - * If the map skips addresses, mark them available. - */ - if(last < base) - map(last, base-last, MemUPA); - switch(e->type){ - case 1: - map(base, len, MemRAM); - break; - case 3: - map(base, len, MemACPI); - break; - default: - map(base, len, MemReserved); - } - last = base + len; - if(last == 0) - break; - } - if(last != 0) - map(last, -last, MemUPA); - return 0; -} - -void -meminit(void) -{ - int i; - Map *mp; - Confmem *cm; - uintptr lost; - - umbscan(); - lowraminit(); - e820scan(); - - /* - * Set the conf entries describing banks of allocatable memory. - */ - for(i=0; ibase = mp->addr; - cm->npage = mp->size/BY2PG; - } - - lost = 0; - for(; ipml4, va, l, 1); + if(pte == nil){ + pte = mmuwalk(m->pml4, va, ++l, 0); if(pte && (*pte & PTESIZE)){ flags |= PTESIZE; z = va & (PGLSZ(l)-1); @@ -384,6 +384,29 @@ pmap(uintptr *pml4, uintptr pa, uintptr va, vlong size) } } +void +punmap(uintptr va, vlong size) +{ + uintptr *pte; + int l; + + va = PPN(va); + while(size > 0){ + if((va % PGLSZ(1)) != 0 || size < PGLSZ(1)) + ptesplit(m->pml4, va); + l = 0; + pte = mmuwalk(m->pml4, va, l, 0); + if(pte == nil && (va % PGLSZ(1)) == 0 && size >= PGLSZ(1)) + pte = mmuwalk(m->pml4, va, ++l, 0); + if(pte){ + *pte = 0; + invlpg(va); + } + va += PGLSZ(l); + size -= PGLSZ(l); + } +} + static void mmuzap(void) { @@ -584,7 +607,7 @@ vmap(uintptr pa, int size) pa -= o; va -= o; size += o; - pmap(m->pml4, pa | PTEUNCACHED|PTEWRITE|PTENOEXEC|PTEVALID, va, size); + pmap(pa | PTEUNCACHED|PTEWRITE|PTENOEXEC|PTEVALID, va, size); return (void*)(va+o); } @@ -667,7 +690,7 @@ preallocpages(void) pm->npage = (top - pm->base)/BY2PG; va = base + VMAP; - pmap(m->pml4, base | PTEGLOBAL|PTEWRITE|PTENOEXEC|PTEVALID, va, psize); + pmap(base | PTEGLOBAL|PTEWRITE|PTENOEXEC|PTEVALID, va, psize); palloc.pages = (void*)(va + tsize); From 30cbaa5c48160411631f2cd6768025a377cd0bec Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 4 Apr 2020 16:50:37 +0200 Subject: [PATCH 5/6] kernel: remove scheddump() comment for delay() in */fns.h --- sys/src/9/bcm/fns.h | 2 +- sys/src/9/kw/fns.h | 2 +- sys/src/9/omap/fns.h | 2 +- sys/src/9/teg2/fns.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/src/9/bcm/fns.h b/sys/src/9/bcm/fns.h index a2b8d16f8..dacbe72ec 100644 --- a/sys/src/9/bcm/fns.h +++ b/sys/src/9/bcm/fns.h @@ -120,7 +120,7 @@ extern int fpuemu(Ureg*); /* * Things called from port. */ -extern void delay(int); /* only scheddump() */ +extern void delay(int); extern int islo(void); extern void microdelay(int); /* only edf.c */ extern void evenaddr(uintptr); diff --git a/sys/src/9/kw/fns.h b/sys/src/9/kw/fns.h index e4cb96857..703e8c503 100644 --- a/sys/src/9/kw/fns.h +++ b/sys/src/9/kw/fns.h @@ -118,7 +118,7 @@ extern Block* uciallocb(int); /* * Things called from port. */ -extern void delay(int); /* only scheddump() */ +extern void delay(int); extern int islo(void); extern void microdelay(int); /* only edf.c */ extern void evenaddr(uintptr); diff --git a/sys/src/9/omap/fns.h b/sys/src/9/omap/fns.h index 4e239355c..68a929826 100644 --- a/sys/src/9/omap/fns.h +++ b/sys/src/9/omap/fns.h @@ -133,7 +133,7 @@ extern void ucfreeb(Block*); /* * Things called from port. */ -extern void delay(int); /* only scheddump() */ +extern void delay(int); extern int islo(void); extern void microdelay(int); /* only edf.c */ extern void evenaddr(uintptr); diff --git a/sys/src/9/teg2/fns.h b/sys/src/9/teg2/fns.h index 9ddec97b2..62e253c27 100644 --- a/sys/src/9/teg2/fns.h +++ b/sys/src/9/teg2/fns.h @@ -190,7 +190,7 @@ extern void ucfreeb(Block*); /* * Things called from port. */ -extern void delay(int); /* only scheddump() */ +extern void delay(int); extern int islo(void); extern void microdelay(int); /* only edf.c */ extern void evenaddr(uintptr); From 339112abc350b0b50ed49a1c92911506025117c7 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 4 Apr 2020 16:52:08 +0200 Subject: [PATCH 6/6] mtx, ppc: use proctab() to index into process table --- sys/src/9/mtx/mmu.c | 5 +++-- sys/src/9/ppc/mmu.c | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sys/src/9/mtx/mmu.c b/sys/src/9/mtx/mmu.c index c4030ce8f..7afd68a3f 100644 --- a/sys/src/9/mtx/mmu.c +++ b/sys/src/9/mtx/mmu.c @@ -85,10 +85,11 @@ mmusweep(void*) sweepcolor = m->sweepcolor; x = splhi(); - p = proctab(0); - for(i = 0; i < conf.nproc; i++, p++) + for(i = 0; i < conf.nproc; i++) { + p = proctab(i); if(PIDCOLOR(p->mmupid) == sweepcolor) p->mmupid = 0; + } splx(x); ptab = (ulong*)m->ptabbase; diff --git a/sys/src/9/ppc/mmu.c b/sys/src/9/ppc/mmu.c index 88ef49e2d..59e59c229 100644 --- a/sys/src/9/ppc/mmu.c +++ b/sys/src/9/ppc/mmu.c @@ -89,10 +89,11 @@ mmusweep(void*) sweepcolor = m->sweepcolor; x = splhi(); - p = proctab(0); - for(i = 0; i < conf.nproc; i++, p++) + for(i = 0; i < conf.nproc; i++){ + p = proctab(i); if(PIDCOLOR(p->mmupid) == sweepcolor) p->mmupid = 0; + } splx(x); ptab = (ulong*)m->ptabbase; @@ -125,9 +126,10 @@ newmmupid(void) m->mmupid = PIDBASE; x = splhi(); tlbflushall(); - p = proctab(0); - for(i = 0; i < conf.nproc; i++, p++) + for(i = 0; i < conf.nproc; i++){ + p = proctab(i); p->mmupid = 0; + } splx(x); wakeup(&m->sweepr); }