arm:no longer rely on a 1:1 phys mapping for device memory.
Change-Id: Ie3f61069f882c37dbb81dee813fdfd883e7468cf
This commit is contained in:
parent
a74251eb16
commit
a5a693a046
6 changed files with 220 additions and 5 deletions
|
@ -53,6 +53,67 @@ extern void * k_stacks;
|
||||||
+ 2 * ((cpu) + 1) * K_STACK_SIZE))
|
+ 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. */
|
/* functions defined in architecture-independent kernel source. */
|
||||||
#include "kernel/proto.h"
|
#include "kernel/proto.h"
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ static int freepdes[MAXFREEPDES];
|
||||||
|
|
||||||
static u32_t phys_get32(phys_bytes v);
|
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)
|
void mem_clear_mapcache(void)
|
||||||
{
|
{
|
||||||
|
@ -260,7 +262,7 @@ vir_bytes bytes; /* # of bytes to be copied */
|
||||||
phys = 0;
|
phys = 0;
|
||||||
} else {
|
} else {
|
||||||
if(phys == 0)
|
if(phys == 0)
|
||||||
panic("vm_lookup returned phys: %d", phys);
|
panic("vm_lookup returned phys: 0x%lx", phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(phys == 0) {
|
if(phys == 0) {
|
||||||
|
@ -692,6 +694,8 @@ int arch_phys_map(const int index,
|
||||||
int *flags)
|
int *flags)
|
||||||
{
|
{
|
||||||
static int first = 1;
|
static int first = 1;
|
||||||
|
kern_phys_map *phys_maps;
|
||||||
|
|
||||||
int freeidx = 0;
|
int freeidx = 0;
|
||||||
u32_t glo_len = (u32_t) &usermapped_nonglo_start -
|
u32_t glo_len = (u32_t) &usermapped_nonglo_start -
|
||||||
(u32_t) &usermapped_start;
|
(u32_t) &usermapped_start;
|
||||||
|
@ -709,6 +713,14 @@ int arch_phys_map(const int index,
|
||||||
if(usermapped_glo_index != -1)
|
if(usermapped_glo_index != -1)
|
||||||
first_um_idx = usermapped_glo_index;
|
first_um_idx = usermapped_glo_index;
|
||||||
first = 0;
|
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) {
|
if(index == usermapped_glo_index) {
|
||||||
|
@ -751,12 +763,26 @@ int arch_phys_map(const int index,
|
||||||
*flags = VMMF_USER;
|
*flags = VMMF_USER;
|
||||||
return OK;
|
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;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_phys_map_reply(const int index, const vir_bytes addr)
|
int arch_phys_map_reply(const int index, const vir_bytes addr)
|
||||||
{
|
{
|
||||||
|
kern_phys_map *phys_maps;
|
||||||
|
|
||||||
if(index == first_um_idx) {
|
if(index == first_um_idx) {
|
||||||
u32_t usermapped_offset;
|
u32_t usermapped_offset;
|
||||||
assert(addr > (u32_t) &usermapped_start);
|
assert(addr > (u32_t) &usermapped_start);
|
||||||
|
@ -797,16 +823,46 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
|
||||||
return OK;
|
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;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_enable_paging(struct proc * caller)
|
int arch_enable_paging(struct proc * caller)
|
||||||
{
|
{
|
||||||
|
kern_phys_map *phys_maps;
|
||||||
assert(caller->p_seg.p_ttbr);
|
assert(caller->p_seg.p_ttbr);
|
||||||
|
|
||||||
|
|
||||||
/* load caller's page table */
|
/* load caller's page table */
|
||||||
switch_address_space(caller);
|
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;
|
device_mem = (char *) device_mem_vaddr;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -817,3 +873,64 @@ void release_address_space(struct proc *pr)
|
||||||
pr->p_seg.p_ttbr_v = NULL;
|
pr->p_seg.p_ttbr_v = NULL;
|
||||||
barrier();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,22 @@
|
||||||
#include <machine/cpu.h>
|
#include <machine/cpu.h>
|
||||||
#include <minix/type.h>
|
#include <minix/type.h>
|
||||||
#include <io.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 {
|
static struct omap_intr {
|
||||||
vir_bytes base;
|
vir_bytes base;
|
||||||
|
int size;
|
||||||
} omap_intr;
|
} omap_intr;
|
||||||
|
|
||||||
|
|
||||||
|
static kern_phys_map intr_phys_map;
|
||||||
|
|
||||||
int intr_init(const int auto_eoi)
|
int intr_init(const int auto_eoi)
|
||||||
{
|
{
|
||||||
#ifdef DM37XX
|
#ifdef DM37XX
|
||||||
|
@ -16,6 +26,9 @@ int intr_init(const int auto_eoi)
|
||||||
#ifdef AM335X
|
#ifdef AM335X
|
||||||
omap_intr.base = OMAP3_AM335X_INTR_BASE;
|
omap_intr.base = OMAP3_AM335X_INTR_BASE;
|
||||||
#endif
|
#endif
|
||||||
|
omap_intr.size = 0x1000 ; /* 4K */
|
||||||
|
|
||||||
|
kern_phys_map_ptr(omap_intr.base,omap_intr.size,&intr_phys_map,&omap_intr.base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,27 @@
|
||||||
#include <machine/cpu.h>
|
#include <machine/cpu.h>
|
||||||
#include <minix/type.h>
|
#include <minix/type.h>
|
||||||
#include <io.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"
|
#include "omap_serial.h"
|
||||||
|
|
||||||
|
|
||||||
struct omap_serial {
|
struct omap_serial {
|
||||||
vir_bytes base;
|
vir_bytes base;
|
||||||
|
vir_bytes size;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct omap_serial omap_serial = {
|
static struct omap_serial omap_serial = {
|
||||||
.base = 0,
|
.base = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static kern_phys_map serial_phys_map;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In kernel serial for the omap. The serial driver like most other
|
* 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.
|
* drivers needs to be started early and even before the MMU is turned on.
|
||||||
|
@ -37,6 +48,10 @@ void omap3_ser_init(){
|
||||||
#ifdef AM335X
|
#ifdef AM335X
|
||||||
omap_serial.base = OMAP3_AM335X_DEBUG_UART_BASE;
|
omap_serial.base = OMAP3_AM335X_DEBUG_UART_BASE;
|
||||||
#endif
|
#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);
|
assert(omap_serial.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <machine/cpu.h>
|
#include <machine/cpu.h>
|
||||||
#include <minix/mmio.h>
|
#include <minix/mmio.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -141,10 +142,16 @@ int omap3_register_timer_handler(const irq_handler_t handler)
|
||||||
return 0;
|
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)
|
void omap3_frclock_init(void)
|
||||||
{
|
{
|
||||||
u32_t tisr;
|
u32_t tisr;
|
||||||
|
|
||||||
|
kern_phys_map_ptr(fr_timer.base,ARM_PAGE_SIZE,&fr_timer_phys_map,&fr_timer.base);
|
||||||
/* enable the clock */
|
/* enable the clock */
|
||||||
#ifdef AM335X
|
#ifdef AM335X
|
||||||
/* Disable the module and wait for the module to be disabled */
|
/* 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)
|
void omap3_timer_init(unsigned freq)
|
||||||
{
|
{
|
||||||
u32_t tisr;
|
u32_t tisr;
|
||||||
|
kern_phys_map_ptr(timer.base,ARM_PAGE_SIZE,&timer_phys_map,&timer.base);
|
||||||
#ifdef AM335X
|
#ifdef AM335X
|
||||||
/* disable the module and wait for the module to be disabled */
|
/* disable the module and wait for the module to be disabled */
|
||||||
set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,CM_MODULEMODE_DISABLED);
|
set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,CM_MODULEMODE_DISABLED);
|
||||||
|
|
|
@ -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 minix_shutdown(timer_t *t) { arch_shutdown(RBT_PANIC); }
|
||||||
void busy_delay_ms(int x) { }
|
void busy_delay_ms(int x) { }
|
||||||
int raise(int n) { panic("raise(%d)\n", n); }
|
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) {};
|
||||||
|
|
Loading…
Reference in a new issue