panthema / 2006 / SDIOS06 / sdios06 / util / kickstart / mbi-ia32.cc (Download File)
/*********************************************************************
 *                
 * Copyright (C) 2003-2004,  Karlsruhe University
 *                
 * File path:     mbi-ia32.cc
 * Description:   IA32 specific multiboot info stuff
 *                
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *                
 * $Id: mbi-ia32.cc,v 1.1.4.3 2004/11/23 14:34:37 skoglund Exp $
 *                
 ********************************************************************/
#include <config.h>
#include <l4io.h>
#include <l4/kip.h>

#include "kickstart.h"
#include "mbi.h"
#include "kipmgr.h"

extern unsigned int max_phys_mem;
extern unsigned int additional_kmem_size;

template<typename T>
static inline T min(T v1, T v2)
{
	if(v1 < v2)
		return v1;
		
	return v2;
}

// The kernel cannot use memory beyond this limit
static const L4_Word64_t MAX_KMEM_END = 240*1024*1024;

L4_Word_t grub_mbi_ptr;
L4_Word_t grub_mbi_flags;


class mmap_t {
public:
    L4_Word32_t   desc_size;
    L4_Word64_t   base;
    L4_Word64_t   size;
    L4_Word32_t   type;
};


mbi_t* mbi_t::prepare(void)
{
    if (grub_mbi_flags == 0x2BADB002)
        return (mbi_t*) grub_mbi_ptr;
    else
        return 0;
}


void install_memory(mbi_t * mbi, kip_manager_t* kip)
{
    // Mark all physical memory as shared by default to allow for
    // device access
    kip->dedicate_memory(0x0, ~0UL, L4_SharedMemoryType, 0);

    // Does the MBI contain a reference to the BIOS memory map?
    if (mbi->flags.mmap)
    {
        // Pointer to first entry in table
        mmap_t* m = (mmap_t*) mbi->mmap_addr;

        // Iterate over all entries
        while ((L4_Word_t) m < (mbi->mmap_addr + mbi->mmap_length))
        {
            /* Limit physical memory if necessary (max_phys_mem != 0)
               We assume that there one big chunk of main memory that
               is larger than 1MB, so we simply adjust its size. */
            if ((max_phys_mem != 0) && (m->size > 1024ULL*1024ULL))
                m->size = max_phys_mem - m->base;

            /* Mark "usable" memory (type=1) as conventional physical
               memory, everything else as architecture specific with
               the BIOS memory map type as subtype */
            kip->dedicate_memory(m->base, m->base + m->size - 1,
                                 (m->type == 1)
                                 ? L4_ConventionalMemoryType
                                 : L4_ArchitectureSpecificMemoryType,
                                 m->type);

            /* Skip forward by the number of bytes specified in the
               structure. This can be more than just the 24 bytes */
            m = (mmap_t*) ((L4_Word_t) m + 4 + m->desc_size);
        }

        if (additional_kmem_size)
        {
            // Second round: Find a suitable KMEM area
            m = (mmap_t*) mbi->mmap_addr;
            // Iterate over all entries
            while ((L4_Word_t) m < (mbi->mmap_addr + mbi->mmap_length))
            {
                if ((m->type == 1) &&
                    (m->size >= additional_kmem_size) &&
                    (m->base <= (MAX_KMEM_END-additional_kmem_size)))
                {
                    L4_Word_t base, end;
                    
                    // Make sure the end is within kernel's reach
                    end = min(m->base+m->size, MAX_KMEM_END);
                    base = end - additional_kmem_size;

                    // Mark the memory block as in use by the kernel
                    kip->dedicate_memory(base, end - 1, 
                                         L4_ReservedMemoryType, 0);
                    // Stop looking
                    break;
                }
                /* Skip forward by the number of bytes specified in the
                   structure. This can be more than just the 24 bytes */
                m = (mmap_t*) ((L4_Word_t) m + 4 + m->desc_size);
            }

        }
    }
    else
    {
        l4_printf("No BIOS memory map. Using old-style MBI fields.\n");

        // mbi.mem_lower is the number of KBs below 1MB starting at 0
        kip->dedicate_memory(0x00000000ULL,
                             mbi->mem_lower * 1024ULL - 1, 
                             L4_ConventionalMemoryType, 0);

        // mbi.mem_upper is the number of KBs above 1MB
        L4_Word_t end = 0x00100000ULL + mbi->mem_upper * 1024ULL;

        // Override the end of physical memory if requested
        if (max_phys_mem != 0)
            end = max_phys_mem;

        kip->dedicate_memory(0x00100000ULL, end - 1, 
                             L4_ConventionalMemoryType, 0);

        if (additional_kmem_size)
        {
            /* Mark a memory block of appropriate size at the end of
               conventional memory as reserved for the kernel */
            kip->dedicate_memory(end - additional_kmem_size, end - 1,
                                 L4_ReservedMemoryType, 0);
        }
    }

    /* The standard PC's VGA memory hasn't been seen in any BIOS
     * memory map so far. So we fake an entry for it. */
    kip->dedicate_memory(0xA0000, 0xC0000 - 1, 
                         L4_SharedMemoryType, 0);
    
    /* Standard PC's may have VGA and Extension ROMs -- fake
     * another entry */
    kip->dedicate_memory(0xC0000, 0xF0000 - 1, 
                         L4_SharedMemoryType, 0);
}