http://wiki.freebsd.org/FreeBSD/arm/OMAP

The Texas Instruments OMAP CPUs are primarily designed for multimedia applications, but are used in a number of handhelds. The family consists of CPUs based on ARMv7, ARMv9 and ARM Cortex A8 cores, often coupled with one or more DSPs, GSM/GPRS digital baseband and/or graphics accelerators. It would be good to see if a port of FreeBSD to this family was feasable. The CPU only seems to support the Thumb-2 instruction set.

The Beagle Board is a low cost board based around the OMAP3530 (ARM Cortex-A8 core, TMS320C64x+ DSP and PowerVR SGX530 GPU) that may be a good board to develop on. It has 128Mb RAM, 256MbNAND Flash, JTAG, USB, RS-232, video out and sound. It lacks a network interface, but does have an expansion port including I2C, so it's possible ic(4) could be used for networking.

Also of interest may be the Pandora console, which is also based around the OMAP3530 CPU and runs Linux by default. Although it is only available currently to developers, it may well prove to be a good dev platform as it appears to have RS232, accessible JTAG, an open developer community at http://www.openpandora.org/as well as being well documented.

Useful links:

http://en.wikipedia.org/wiki/OMAP
http://www.beagleboard.org
http://en.wikipedia.org/wiki/Pandora_(console)

And hosted at Google, there is only a miserable ONE file:

http://code.google.com/p/freebsd-bgb/source/checkout


/*-
 * Copyright (c) 2009 Guillaume Ballet
 * All rights reserved.
 *
 * 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.
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/types.h>
#include <sys/param.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <sys/pcpu.h>
#include <sys/cons.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <machine/pmap.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <machine/pcb.h>
#include <machine/machdep.h>
#include <machine/undefined.h>
#include <sys/kdb.h>
#define DEBUG_INITARM
#include "beagle.h"

struct pcpu    __pcpu;
struct pcpu    *pcpup = &__pcpu;

/* Physical page ranges */
vm_paddr_t    phys_avail[4];
vm_paddr_t    dump_avail[4];

struct pv_addr systempage;

#define FIQ_STACK_SIZE    1
#define IRQ_STACK_SIZE    1
#define ABT_STACK_SIZE    1
#define UND_STACK_SIZE    1

#define NUM_KERNEL_PTS    12

extern int _start[];
extern int _end[];

extern void beagle_putchar(unsigned char);

extern u_int data_abort_handler_address;
extern u_int prefetch_abort_handler_address;
extern u_int undefined_handler_address;

/* struct pv_addr    msgbuf */
static struct pv_addr    fiqstack;                /* Stack page descriptors for all modes */
static struct pv_addr    irqstack;
static struct pv_addr    undstack;
static struct pv_addr    abtstack;
static struct pv_addr    kernelstack;
static struct pv_addr    kernel_l1pt;                /* Level-1 page table entry */
static struct pv_addr    kernel_page_tables[NUM_KERNEL_PTS];    /* Level-2 page table entries for the kernel */

static struct trapframe    proc0_tf;

#define PHYS2VIRT(x)    ((x - KERNPHYSADDR) + KERNVIRTADDR)
#define VIRT2PHYS(x)    ((x - KERNVIRTADDR) + KERNPHYSADDR)

/* Macro stolen from the Xscale part, used to simplify TLB allocation */
#define valloc_pages(var, np)                   \
        alloc_pages((var).pv_pa, (np));         \
        (var).pv_va = PHYS2VIRT((var).pv_pa);    \
#ifdef VERBOSE_INIT_ARM                \
    printf("va=%p pa=%p\n", (void*)(var).pv_va, (void*)(var).pv_pa);    \
#endif

#define alloc_pages(var, np)                    \
        (var) = freemempos;             \
        freemempos += (np * PAGE_SIZE);         \
        memset((char *)(var), 0, ((np) * PAGE_SIZE));

#define round_L_page(x) (((x) + L2_L_OFFSET) & L2_L_FRAME)

#define VERBOSE_INIT_ARM

static const struct pmap_devmap omap3_devmap[] = {
    /*
         * For the moment, map devices with PA==VA.
     */

    {
        /* 1MB of L4, covering the MMU registers */
        0x48000000,
        0x48000000,
        0x00100000,
        VM_PROT_READ|VM_PROT_WRITE,
        PTE_NOCACHE
    },
    {
        /* 1MB of L4, covering the console */
        0x49000000,
        0x49000000,
        0x00100000,
        VM_PROT_READ|VM_PROT_WRITE,
        PTE_NOCACHE
    },
    { 0, 0, 0, 0, 0 }    /* Array terminator */
};

void *initarm(void *arg1, void *arg2)
{

    vm_offset_t    freemempos;
    int        i, j;
    volatile int    cpsr;
#ifdef VERBOSE_INIT_ARM
    long        *reg;
#endif

    pcpu_init(pcpup, 0, sizeof(struct pcpu));
    PCPU_SET(curthread, &thread0);

    set_cpufuncs();

    cpu_initclocks();

    /* Console subsystem */
    cninit();
#ifdef VERBOSE_INIT_ARM
    printf("==== MMU registers ====\n");
    for (reg=(long*)0x480bd400; reg<(long*)0x480bd46c; reg++)
        printf("%p:\t%#x\n", reg, (unsigned int)*reg);

    __asm __volatile("mrc    p15, 0, %0, c1, c0, 0 ;" : "=r" (cpsr));
    printf("cp15:c1:c0=%#x\n", cpsr);

    printf("PMAP_DOMAIN_KERNEL=%#x\n", PMAP_DOMAIN_KERNEL);
#endif

    /* ** Page reservations ************************************************************************* */

    /* Initialize freemempos. Pages are allocated from the end of the RAM's first 64MB, as it is what */
    /* is covered by the default TLB in locore.S.                              */
    freemempos    = VIRT2PHYS(round_L_page( /*(long)_end)) */ fake_preload_metadata()));
    printf("freemempos=%p %d %d\n", (void*)freemempos, L1_S_SIZE, L1_TABLE_SIZE);

    /* Reserve L1 table pages now, as freemempos is 64K-aligned */
    valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
    printf("l1pa=%p l1va=%p\n", (void*)kernel_l1pt.pv_pa, (void*)kernel_l1pt.pv_va);

    /* Reserve the paging system pages, page #0 is reserved as a L2 table for the exception vector. */
    for (i=0; i<NUM_KERNEL_PTS; i++) {
        if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
            valloc_pages(kernel_page_tables[i], L2_TABLE_SIZE / PAGE_SIZE);
        } else {
            j                = i % (PAGE_SIZE / L2_TABLE_SIZE_REAL);
            kernel_page_tables[i].pv_pa    = kernel_page_tables[i - j].pv_pa + (j * L2_TABLE_SIZE_REAL);
            kernel_page_tables[i].pv_va    = kernel_page_tables[i - j].pv_va + (j * L2_TABLE_SIZE_REAL);
        }
    }

    /* Handle system page, where the interrupt vector is stored. */
    valloc_pages(systempage, 1);
    systempage.pv_va    = ARM_VECTORS_HIGH;

    /* Stack pages */
    valloc_pages(fiqstack, FIQ_STACK_SIZE);
    valloc_pages(irqstack, IRQ_STACK_SIZE);
    valloc_pages(abtstack, ABT_STACK_SIZE);
    valloc_pages(undstack, UND_STACK_SIZE);
    valloc_pages(kernelstack, KSTACK_PAGES + 1);

    /* ** Build the TLBs **************************************************************************** */

    /* L2 table for the exception vector */
    pmap_link_l2pt(kernel_l1pt.pv_va, ARM_VECTORS_HIGH & ~(0x100000 - 1), &kernel_page_tables[0]);

    /* Insert a reference to the kernel L2 page tables into the L1 page. */
    for (i=1; i<NUM_KERNEL_PTS; i++) {
        pmap_link_l2pt(kernel_l1pt.pv_va,
                KERNVIRTADDR + (i-1) * 0x100000,
                &kernel_page_tables[i]);
    }

    /* Map the kernel */
    size_t    textsize = round_L_page((long)etext - KERNVIRTADDR);
    size_t    totalsize = round_L_page((long) _end - KERNVIRTADDR);

#ifdef VERBOSE_INIT_ARM
    printf(".text=%#x total=%#x _end=%#x %#x %#x\n", textsize, totalsize, (unsigned int)_end, (unsigned int) etext, KERNVIRTADDR);
#endif

    vm_offset_t    offset = 0;
    offset += pmap_map_chunk(kernel_l1pt.pv_va, KERNVIRTADDR + offset,
            KERNPHYSADDR + offset, textsize,
            VM_PROT_READ|VM_PROT_EXECUTE, PTE_CACHE);

    offset += pmap_map_chunk(kernel_l1pt.pv_va, KERNVIRTADDR + offset,
            KERNPHYSADDR + offset, totalsize - textsize,
            VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);

    /* Map the L1 page table */
    pmap_map_chunk(kernel_l1pt.pv_va,
            kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
            L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE,
            PTE_PAGETABLE);

    /* Map the L2 page tables */
    for (i=0; i<NUM_KERNEL_PTS; i++) {
        pmap_map_chunk(kernel_l1pt.pv_va,
            kernel_page_tables[i].pv_va, kernel_page_tables[i].pv_pa,
            L2_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE,
            PTE_PAGETABLE);
    }

    /* Map the interrupt vector */
    pmap_map_entry(kernel_l1pt.pv_va, ARM_VECTORS_HIGH, systempage.pv_pa,
            VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);

    /* Map the stack pages */
#ifdef VERBOSE_INIT_ARM
    printf("Mapping the stack pages\n");
#endif
    pmap_map_chunk(kernel_l1pt.pv_pa, fiqstack.pv_va, fiqstack.pv_pa,
            FIQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
    pmap_map_chunk(kernel_l1pt.pv_pa, irqstack.pv_va, irqstack.pv_pa,
            IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
    pmap_map_chunk(kernel_l1pt.pv_pa, abtstack.pv_va, abtstack.pv_pa,
            ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
    pmap_map_chunk(kernel_l1pt.pv_pa, undstack.pv_va, undstack.pv_pa,
            UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
    pmap_map_chunk(kernel_l1pt.pv_pa, kernelstack.pv_va, kernelstack.pv_pa,
            (KSTACK_PAGES+1) * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);

    /* Device map */
    pmap_devmap_bootstrap(kernel_l1pt.pv_pa, omap3_devmap);
    //dump_table((void*)kernel_l1pt.pv_va, 0, 16384, "initial");

    /* ** Switch L1 TLB table *********************************************************************** */
#ifdef VERBOSE_INIT_ARM
    printf("DOMAIN_CLIENT=%#x, PMAP_DOMAIN_KERNEL=%#x\n", DOMAIN_CLIENT, PMAP_DOMAIN_KERNEL);
#endif
    cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_MANAGER);
    setttb(kernel_l1pt.pv_pa);
    cpu_tlb_flushID();
    //cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)));
    /* Do not set the domain for now. The beagle board seems to have problems with the backward-compatibility mode */

#ifdef VERBOSE_INIT_ARM
    printf("Now using the new L1.\n");
#endif

    /* ** Set stack frames ************************************************************************** */
    set_stackptr(PSR_FIQ32_MODE, fiqstack.pv_va + FIQ_STACK_SIZE * PAGE_SIZE);
    set_stackptr(PSR_IRQ32_MODE, irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
    set_stackptr(PSR_ABT32_MODE, abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
    set_stackptr(PSR_UND32_MODE, undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);

#ifdef VERBOSE_INIT_ARM
    printf("STACK: %p\n", (void *)(fiqstack.pv_va + FIQ_STACK_SIZE * PAGE_SIZE));
    printf("STACK: %p\n", (void*)(irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE));
    printf("STACK: %p\n", (void *)(abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE));
    printf("STACK: %p\n", (void *)(undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE));
#endif

    /* ** Miscellaneous ***************************************************************************** */

    /* Exception handlers */
    data_abort_handler_address    = (u_int) data_abort_handler;
    prefetch_abort_handler_address    = (u_int) prefetch_abort_handler;
    undefined_handler_address    = (u_int) undefinedinstruction_bounce;
    undefined_init();

    /* Prepares the context of the first process */
    proc_linkup(&proc0, &thread0);
    thread0.td_kstack        = kernelstack.pv_va;
    thread0.td_pcb            = (struct pcb *) (thread0.td_kstack + (KSTACK_PAGES + 1) * PAGE_SIZE) - 1;
    thread0.td_pcb->pcb_flags    = 0;
    thread0.td_frame        = &proc0_tf;
    pcpup->pc_curpcb        = thread0.td_pcb;

    /* Exception vector */
#ifdef VERBOSE_INIT_ARM
    printf("Exception vector at (%#x)\n", ((unsigned int *)systempage.pv_va)[0]);
#endif
    arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);

    /* First unbacked address of KVM */
    pmap_curmaxkvaddr    = KERNVIRTADDR + 0x100000 * NUM_KERNEL_PTS;

    /* Physical ranges of available memory. */
    phys_avail[0]    = freemempos;
    phys_avail[1]    = PHYSADDR + BEAGLE_MEMSIZE;
    phys_avail[2]    = 0;
    phys_avail[3]    = 0;

    dump_avail[0]    = PHYSADDR;
    dump_avail[1]    = PHYSADDR + BEAGLE_MEMSIZE;
    dump_avail[2]    = 0;
    dump_avail[3]    = 0;

    physmem        = BEAGLE_MEMSIZE / PAGE_SIZE;

    init_param1();
    init_param2(physmem);

    pmap_bootstrap((freemempos&0x007fffff)|0xc0000000, KERNVIRTADDR+0x10000000, &kernel_l1pt);

    /* Locking system */
    mutex_init();

    /* Kernel debugger */
    kdb_init();

    /* initarm returns the address of the kernel stack */
    return (void *)(kernelstack.pv_va + (KSTACK_PAGES + 1) * PAGE_SIZE);
}

Reply via email to