arm:no longer rely on a 1:1 phys mapping for device memory.

Change-Id: Ie3f61069f882c37dbb81dee813fdfd883e7468cf
This commit is contained in:
Kees Jongenburger 2013-06-11 16:07:43 +02:00 committed by Gerrit Code Review
parent a74251eb16
commit a5a693a046
6 changed files with 220 additions and 5 deletions

View file

@ -53,6 +53,67 @@ extern void * k_stacks;
+ 2 * ((cpu) + 1) * K_STACK_SIZE))
/*
* Definition of a callback used when a memory map changes it's base address
*/
typedef int (*kern_phys_map_mapped)(vir_bytes id, vir_bytes new_addr );
/*
* struct used internally by memory.c to keep a list of
* items to map. These should be staticaly allocated
* in the individual files and passed as argument.
* The data doesn't need to be initialized. See omap_serial for
* and example usage.
*/
typedef struct kern_phys_map{
phys_bytes addr; /* The physical address to map */
vir_bytes size; /* The size of the mapping */
vir_bytes id; /* an id passed to the callback */
kern_phys_map_mapped cb; /* the callback itself */
phys_bytes vir; /* The virtual address once remapped */
int index; /* index */
struct kern_phys_map *next; /* pointer to the next */
} kern_phys_map ;
/*
* Request an in kernel physical mapping.
*
* On ARM many devices are memory mapped and some of these devices
* are used in the kernel. These device can be things like serial
* lines, interrupt controller and clocks. The kernel needs to be
* able to access these devices at the various stages of booting.
* During startup, until arch_enable_paging is called, it is the
* kernel whom is controlling the mappings and it often needs to
* access the memory using a 1:1 mapping between virtual and
* physical memory.
*
* Once processes start to run it is no longer desirable for the
* kernel to have devices mapped in the middle of the process
* address space.
*
* This method requests the memory manager to map base_address/size
* in the kernel address space and call back the kernel when this
* mapping takes effect (after enable_paging).
*
* Before the callback is called it is up to the kernel to use it's
* own addressing. The callback will happen *after* the kernel lost
* it's initial mapping. It it therefore not safe to use the initial
* mapping in the callback. It also is not possible to use printf for
* the same reason.
*/
int kern_req_phys_map( phys_bytes base_address, vir_bytes io_size,
kern_phys_map * priv, kern_phys_map_mapped cb,
vir_bytes id);
/*
* Request a physical mapping and put the result in the given prt
* Note that ptr will only be valid once the callback happend.
*/
int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size,
kern_phys_map * priv, vir_bytes ptr);
/* functions defined in architecture-independent kernel source. */
#include "kernel/proto.h"

View file

@ -29,6 +29,8 @@ static int freepdes[MAXFREEPDES];
static u32_t phys_get32(phys_bytes v);
/* list of requested physical mapping */
static kern_phys_map *kern_phys_map_head;
void mem_clear_mapcache(void)
{
@ -260,7 +262,7 @@ vir_bytes bytes; /* # of bytes to be copied */
phys = 0;
} else {
if(phys == 0)
panic("vm_lookup returned phys: %d", phys);
panic("vm_lookup returned phys: 0x%lx", phys);
}
if(phys == 0) {
@ -692,6 +694,8 @@ int arch_phys_map(const int index,
int *flags)
{
static int first = 1;
kern_phys_map *phys_maps;
int freeidx = 0;
u32_t glo_len = (u32_t) &usermapped_nonglo_start -
(u32_t) &usermapped_start;
@ -709,6 +713,14 @@ int arch_phys_map(const int index,
if(usermapped_glo_index != -1)
first_um_idx = usermapped_glo_index;
first = 0;
/* list over the maps and index them */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
phys_maps->index = freeidx++;
phys_maps = phys_maps->next;
}
}
if(index == usermapped_glo_index) {
@ -750,6 +762,18 @@ int arch_phys_map(const int index,
*len = ARM_PAGE_SIZE;
*flags = VMMF_USER;
return OK;
}
/* if this all fails loop over the maps */
/* list over the maps and index them */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
if(phys_maps->index == index){
*addr = phys_maps->addr;
*len = phys_maps->size;
*flags = VMMF_UNCACHED | VMMF_WRITE;
return OK;
}
phys_maps = phys_maps->next;
}
return EINVAL;
@ -757,6 +781,8 @@ int arch_phys_map(const int index,
int arch_phys_map_reply(const int index, const vir_bytes addr)
{
kern_phys_map *phys_maps;
if(index == first_um_idx) {
u32_t usermapped_offset;
assert(addr > (u32_t) &usermapped_start);
@ -797,16 +823,46 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
return OK;
}
/* if this all fails loop over the maps */
/* list over the maps and index them */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
if(phys_maps->index == index){
assert(phys_maps->cb != NULL);
/* only update the vir addr we are
going to call the callback in enable
paging
*/
phys_maps->vir = addr;
return OK;
}
phys_maps = phys_maps->next;
}
return EINVAL;
}
int arch_enable_paging(struct proc * caller)
{
kern_phys_map *phys_maps;
assert(caller->p_seg.p_ttbr);
/* load caller's page table */
switch_address_space(caller);
/* We have now switched address spaces and the mappings are
valid. We can now remap previous mappings. This is not a
good time to do printf as the initial massing is gone and
the new mapping is not in place */
phys_maps = kern_phys_map_head;
while(phys_maps != NULL){
assert(phys_maps->cb != NULL);
phys_maps->cb(phys_maps->id, phys_maps->vir);
phys_maps = phys_maps->next;
}
device_mem = (char *) device_mem_vaddr;
return OK;
@ -817,3 +873,64 @@ void release_address_space(struct proc *pr)
pr->p_seg.p_ttbr_v = NULL;
barrier();
}
/*
* Request a physical mapping
*/
int kern_req_phys_map( phys_bytes base_address, vir_bytes io_size,
kern_phys_map * priv, kern_phys_map_mapped cb,
vir_bytes id)
{
/* Assign the values to the given struct and add priv
to the list */
assert(base_address != 0);
assert(io_size % ARM_PAGE_SIZE == 0);
assert(cb != NULL);
priv->addr = base_address;
priv->size = io_size;
priv->cb = cb;
priv->id = id;
priv->index = -1;
priv->next = NULL;
if (kern_phys_map_head == NULL){
/* keep a list of items this is the first one */
kern_phys_map_head = priv;
kern_phys_map_head->next = NULL;
} else {
/* insert the item head but first keep track
of the current by putting it in next */
priv->next = kern_phys_map_head;
/* replace the head */
kern_phys_map_head = priv;
}
return 0;
}
/*
* Callback implementation where the id given to the
* kern_phys_map is a pointer to the io map base address.
* this implementation will change that base address.
*/
int kern_phys_map_mapped_ptr(vir_bytes id, phys_bytes address){
*((vir_bytes*)id) = address;
return 0;
}
/*
* Request a physical mapping and put the result in the given prt
* Note that ptr will only be valid once the callback happend.
*/
int kern_phys_map_ptr(
phys_bytes base_address,
vir_bytes io_size,
kern_phys_map * priv,
vir_bytes ptr)
{
return kern_req_phys_map(base_address,io_size,priv,kern_phys_map_mapped_ptr,ptr);
}

View file

@ -2,20 +2,33 @@
#include <machine/cpu.h>
#include <minix/type.h>
#include <io.h>
#include "omap_intr.h"
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "omap_intr.h"
static struct omap_intr {
vir_bytes base;
int size;
} omap_intr;
static kern_phys_map intr_phys_map;
int intr_init(const int auto_eoi)
{
#ifdef DM37XX
omap_intr.base = OMAP3_DM37XX_INTR_BASE;
omap_intr.base = OMAP3_DM37XX_INTR_BASE;
#endif
#ifdef AM335X
omap_intr.base = OMAP3_AM335X_INTR_BASE;
omap_intr.base = OMAP3_AM335X_INTR_BASE;
#endif
omap_intr.size = 0x1000 ; /* 4K */
kern_phys_map_ptr(omap_intr.base,omap_intr.size,&intr_phys_map,&omap_intr.base);
return 0;
}

View file

@ -3,16 +3,27 @@
#include <machine/cpu.h>
#include <minix/type.h>
#include <io.h>
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "kernel/vm.h"
#include "kernel/proto.h"
#include "arch_proto.h"
#include "omap_serial.h"
struct omap_serial {
vir_bytes base;
vir_bytes size;
};
static struct omap_serial omap_serial = {
.base = 0,
};
static kern_phys_map serial_phys_map;
/*
* In kernel serial for the omap. The serial driver like most other
* drivers needs to be started early and even before the MMU is turned on.
@ -37,6 +48,10 @@ void omap3_ser_init(){
#ifdef AM335X
omap_serial.base = OMAP3_AM335X_DEBUG_UART_BASE;
#endif
omap_serial.size = 0x1000 ; /* 4k */
kern_phys_map_ptr(omap_serial.base,omap_serial.size,&serial_phys_map,&omap_serial.base);
assert(omap_serial.base);
}

View file

@ -3,6 +3,7 @@
#include <sys/types.h>
#include <machine/cpu.h>
#include <minix/mmio.h>
#include <assert.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
@ -141,10 +142,16 @@ int omap3_register_timer_handler(const irq_handler_t handler)
return 0;
}
/* meta data for remapping */
static kern_phys_map timer_phys_map;
static kern_phys_map fr_timer_phys_map;
void omap3_frclock_init(void)
{
u32_t tisr;
kern_phys_map_ptr(fr_timer.base,ARM_PAGE_SIZE,&fr_timer_phys_map,&fr_timer.base);
/* enable the clock */
#ifdef AM335X
/* Disable the module and wait for the module to be disabled */
@ -202,6 +209,7 @@ void omap3_frclock_stop()
void omap3_timer_init(unsigned freq)
{
u32_t tisr;
kern_phys_map_ptr(timer.base,ARM_PAGE_SIZE,&timer_phys_map,&timer.base);
#ifdef AM335X
/* disable the module and wait for the module to be disabled */
set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,CM_MODULEMODE_DISABLED);

View file

@ -296,4 +296,5 @@ int send_sig(endpoint_t proc_nr, int sig_nr) { return 0; }
void minix_shutdown(timer_t *t) { arch_shutdown(RBT_PANIC); }
void busy_delay_ms(int x) { }
int raise(int n) { panic("raise(%d)\n", n); }
int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size,
struct kern_phys_map * priv, vir_bytes ptr) {};