Subject: Re: Allocating a buffer in physical memory?
To: Brian Clough <Brian_Clough@phoenix.com>
From: Frank van der Linden <fvdl@wasabisystems.com>
List: tech-kern
Date: 09/24/2001 16:21:08
On Mon, Sep 24, 2001 at 09:50:33AM -0400, Brian Clough wrote:
> I need to set up a buffer below 0xFFFFF in physical memory.  So that a
> real mode VESA BIOS function (called from a kernel driver) can access
> it using a 16:16 segment:offset.
> 
> I tried allocating space on the stack, but during driver initialization the
> stack lives above 1 Mb.  I've tried "mmaping" an anonymous region
> inside the lower 1 Mb, but I don't think that function can be called
> from inside the kernel.  If it can then that should solve my problem.
> 
> Should I be able to call "mmap" from a device driver?  If so, how?
> 
> Otherwise, how can I allocate space (I only need about 100 bytes) in a
> pre-determined range of physical memory?

Normally allocating memory in explicit ranges of memory only needs to
be done when allocatng driver memory for DMA purposes. We use the
bus_dma(9) interface for that. A bus_dma tag describing the ISA
bus will actually allocate physical memory below 1M, since that
is the limit of addressable memory over the ISA bus.

Using bus_dma may not be the best choice for you, since you're probably
not writing an ISA driver. You may want to allocate pages (well, just
one page in this case) using uvm_pglistalloc.

If you want to be able to address the space from your driver as well,
you must map it into kernel virtual space, for example by allocating
a chunk of kernel virtual memory (kvm) with uvm_km_valloc and setting
up the mapping using pmap_enter.

For examples on this, see arch/i386/i386/bus_machdep.c in the kernel
sources, look at _bus_dmamem_alloc_range for uvm_pglistalloc usage,
and _bus_dmamem_map for uvm_km_valloc + pmap_enter.

The short form of it all would be:

	struct pglist list;
	struct vm_page *m;
	paddr_t paddr;
	vaddr_t va;

	uvm_pglistalloc(PAGE_SIZE, 0, 0xfffff, PAGE_SIZE, PAGE_SIZE, &list,
	    1, 0);
	m = mlist.tqh_first;
	paddr = VM_PAGE_TO_PHYS(m);

	va = uvm_km_valloc(kernel_map, PAGE_SIZE);
	pmap_enter(pmap_kernel(), va, paddr, VM_PROT_READ | VM_PROT_WRITE,
	    PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE);
	pmap_update(pmap_kernel());

'va' is now the kernel virtual address through which you can address
this area.

This is pseudo-ish code, and does not do any error checking.. And
typed as I remember it, so check the source code to be sure.

If you're using 1.5.x, pmap_update() will not take an argument.

Allocating memory from a specific range is best done early, during
boot time.

- Frank

-- 
Frank van der Linden                           fvdl@wasabisystems.com
======================================================================
Quality NetBSD CDs, Support & Service.   http://www.wasabisystems.com/