Subversion Repositories HelenOS

Rev

Rev 2258 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2007 Pavel Jancik, Michal Kebrt
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup arm32mm
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <arch/mm/page.h>
  36. #include <genarch/mm/page_pt.h>
  37. #include <arch.h>
  38. #include <mm/page.h>
  39. #include <align.h>
  40. #include <config.h>
  41. #include <arch/exception.h>
  42. #include <typedefs.h>
  43. #include <arch/types.h>
  44. #include <interrupt.h>
  45.  
  46. //TODO: remove in final version
  47. #include "../aux_print/printf.h"
  48.  
  49.  
  50. // localy used types
  51. /**
  52.  * Decribes structure of fault status register in coprocessor 15
  53.  */
  54. typedef struct {
  55.         unsigned status              : 3;
  56.         unsigned domain              : 4;
  57.         unsigned zero            : 1;
  58.         unsigned should_be_zero      : 24;
  59. } __attribute__ ((packed)) fault_status_t;
  60.  
  61. /**
  62.  * Help union used for overcasting integer value into fault_status_t type
  63.  */
  64. typedef union {
  65.     fault_status_t  fsr;
  66.     uint32_t    dummy;
  67. } fault_status_union_t;
  68.  
  69. /**
  70.  * Very simplyfied description of instruction code structure intended for
  71.  * recognising memmory access of instruction ( reads or writes into memmory)
  72.  * more details: see ARM architecture preference chapter:3.1 Instruction set encoding
  73.  */
  74. typedef struct {
  75.         unsigned dummy1              : 4;
  76.         unsigned bit4                : 1;
  77.         unsigned bits567             : 3;
  78.         unsigned dummy               : 12;
  79.         unsigned access              : 1;
  80.         unsigned opcode              : 4;
  81.         unsigned instr_type          : 3;
  82.         unsigned condition       : 4;
  83. } __attribute__ ((packed)) instruction_t;
  84.  
  85. /**
  86.  *  Help union used for overcasting ip register (uint_32_t) value into instruction_t pointer
  87.  */
  88. typedef union {
  89.     instruction_t*  instr;
  90.     uint32_t    ip;
  91. } instruction_union_t;
  92.  
  93. // localy used functions
  94. static fault_status_t read_fault_status_register();
  95. static uintptr_t read_fault_address_register();
  96. static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr);
  97.  
  98.  
  99. /**
  100.  * Initializes kernel adress space page tables, sets abourts exceptions vectors
  101.  */
  102. void page_arch_init(void)
  103. {
  104.     uintptr_t cur;
  105.     int flags;
  106.  
  107.     page_mapping_operations = &pt_mapping_operations;
  108.  
  109.     flags = PAGE_CACHEABLE;
  110.  
  111.     /* PA2KA(identity) mapping for all frames until last_frame */
  112.     for (cur = 0; cur < last_frame; cur += FRAME_SIZE) {
  113.         page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags);
  114.     }
  115.  
  116.     // TODO: move to the kernel space
  117.     page_mapping_insert(AS_KERNEL, 0x00000000, 0x00000000, flags);
  118.     // TODO: remove when aux_printf not needed
  119.     page_mapping_insert(AS_KERNEL, 0x10000000, 0x10000000, flags);
  120.  
  121.     exc_register(EXC_DATA_ABORT,     "page_fault data abort",     (iroutine) data_abourt);
  122.     exc_register(EXC_PREFETCH_ABORT, "page_fault prefetch abort", (iroutine) prefetch_abourt);
  123.  
  124.     as_switch(NULL, AS_KERNEL);
  125.  
  126.     // TODO: register fault routine
  127. }
  128.  
  129. /**
  130.  * Map device into kernel space.
  131.  *
  132.  * This function adds mapping of physical address that is read/write only
  133.  *  from kernel and not bufferable.
  134.  *
  135.  * \param physaddr Physical addres where device is connected
  136.  * \param size Length of area where device is present
  137.  * \return Virtual address where device will be accessable
  138.  * Note: This is copy of IA32 hw_map code
  139.  */
  140. uintptr_t hw_map(uintptr_t physaddr, size_t size)
  141. {
  142.     if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
  143.         panic("Unable to map physical memory %p (%d bytes)", physaddr, size)
  144.  
  145.     uintptr_t virtaddr = PA2KA(last_frame);
  146.     pfn_t i;
  147.     for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++)
  148.         page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), physaddr + PFN2ADDR(i), PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL);
  149.  
  150.     last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
  151.  
  152.     return virtaddr;
  153. }
  154.  
  155. //TODO: remove in final version
  156. static void print_istate(istate_t* istate);
  157. static void print_istate(istate_t* istate) {
  158.  aux_printf("\nIstate dump:\n");
  159.  aux_printf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
  160.  aux_printf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
  161.  aux_printf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
  162.  aux_printf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
  163. }
  164.  
  165. /**
  166.  * \return Value stored in fault status register
  167.  */
  168. static fault_status_t read_fault_status_register() {
  169.         fault_status_union_t tmp;
  170.         asm volatile (
  171.         "mrc p15, 0, %0, c5, c0, 0"
  172.             : "=r"(tmp.dummy)
  173.     );
  174.     return tmp.fsr;
  175. }
  176.  
  177. /**
  178.  * \return Virtual adress. Access on this addres caused exception
  179.  */
  180. static uintptr_t read_fault_address_register() {
  181.         uintptr_t tmp;
  182.     // Fault adress is stored in coprocessor15, register 6
  183.     asm volatile (
  184.         "mrc p15, 0, %0, c6, c0, 0"
  185.         : "=r"(tmp)
  186.     );
  187.     return tmp;
  188. };
  189.  
  190. /**
  191.  * Decode instruction and decide if try to read or write into memmory.
  192.  *
  193.  * \param instr_addr address of instruction which attempts to access into memmory
  194.  * \param badvaddr Virtual address on which instruction tries to access
  195.  * \return type of access into memmory
  196.  *  Note: return PF_ACESS_EXEC if no memmory acess
  197.  */
  198. //TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
  199. pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
  200.         instruction_union_t tmp;
  201.         tmp.ip = instr_addr;
  202.     // get instruction op code
  203.     instruction_t i_code = *(tmp.instr);
  204.  
  205.         aux_printf("get_instruction_memmory_access\n");
  206.     aux_printf(" i_code:%X\n",i_code);
  207.     aux_printf(" i_code.condition:%d\n", i_code.condition);
  208.     aux_printf(" i_code.instr_type:%d\n",i_code.instr_type);
  209.     aux_printf(" i_code.opcode:%d\n",i_code.opcode);
  210.     aux_printf(" i_code.acess:%d\n", i_code.access);
  211.     aux_printf(" i_code.dummy:%d\n", i_code.dummy);
  212.     aux_printf(" i_code.bits567%d\n", i_code.bits567);
  213.     aux_printf(" i_code.bit4:%d\n", i_code.bit4);
  214.     aux_printf(" i_code.dummy1:%d\n", i_code.dummy1);
  215.  
  216.  
  217.         // undefined instructions ... (or special instructions)
  218.     if ( i_code.condition == 0xf ) {
  219.         panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  220.         return PF_ACCESS_EXEC;
  221.     }
  222.  
  223.     // load store instructions
  224.         if ( ( i_code.instr_type == 0x2 ) || // load store immediate offset
  225.              ( i_code.instr_type == 0x3 && i_code.bit4 == 0) || // load store register offset
  226.              ( i_code.instr_type == 0x4 ) || // load store multiple
  227.          ( i_code.instr_type == 0x6 )    // coprocessor load / strore
  228.        ) {
  229.         if ( i_code.access == 1) {
  230.             return PF_ACCESS_READ;
  231.         } else {
  232.             return PF_ACCESS_WRITE;
  233.         }
  234.     };
  235.  
  236.     // swap, swpb instruction
  237.     if ( i_code.instr_type == 0x0 && (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
  238.          i_code.access == 0x0 && i_code.bits567 == 0x4 && i_code.bit4 == 1 )
  239.      {
  240.         /* Swap instructions make read and write in one step.
  241.          * Type of access that caused exception have to page tables and access rights.
  242.          */
  243. //TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
  244. //      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
  245. //  same case as_page_fault .... it's nessesary to solve "stack" problem
  246.                 pte_level1_t* pte = (pte_level1_t*)pt_mapping_operations.mapping_find(AS, badvaddr);
  247.  
  248.         ASSERT(pte);
  249.  
  250.                 /* check if read possible
  251.                  * Note: Don't check PTE_READABLE because it returns 1 everytimes */
  252.         if ( !PTE_PRESENT(pte) ) {
  253.                 return PF_ACCESS_READ;
  254.         }
  255.         if ( !PTE_WRITABLE(pte) ) {
  256.             return PF_ACCESS_WRITE;
  257.         }
  258.         else
  259.             // badvaddr is present readable and writeable but error occured ... why?
  260.             panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  261.     }
  262.     panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  263.     return PF_ACCESS_EXEC;
  264. }
  265.  
  266. /**
  267.  * Routine that solves exception data_abourt
  268.  *  ... you try to load or store value into invalid memmory address
  269.  * \param istate State of CPU when data abourt occured
  270.  * \param n number of exception
  271.  */
  272. //TODO: remove debug prints in final tested version
  273. void data_abourt(int n, istate_t *istate) {
  274.         fault_status_t fsr = read_fault_status_register();
  275.         uintptr_t  page = read_fault_address_register();
  276.  
  277.     pf_access_t access = get_memmory_access_type( istate->lr, page);
  278.  
  279.     print_istate(istate);
  280.     aux_printf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access);
  281.  
  282.         int ret = as_page_fault(page, access, istate);
  283.     aux_printf(" as_page_fault ret:%d\n", ret);
  284.         if (ret == AS_PF_FAULT) {
  285.         fault_if_from_uspace(istate, "Page fault: %#x", page);
  286.  
  287.                 panic("page fault\n");
  288.         }
  289.  
  290.     // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
  291.     panic("page fault ... solved\n");
  292.  
  293. }
  294.  
  295. /**
  296.  * Routine that solves exception prefetch_about
  297.  *  ... you try to execute instruction on invalid address
  298.  * \param istate State of CPU when prefetch abourt occured
  299.  * \param n number of exception
  300.  */
  301. void prefetch_abourt(int n, istate_t *istate) {
  302.  // Prefetch can be made be bkpt instruction
  303.     print_istate(istate);
  304.     aux_printf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr);
  305.  
  306.         int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate);
  307.     aux_printf(" as_page_fault ret:%d\n", ret);
  308.         if (ret == AS_PF_FAULT) {
  309.                 panic("page fault - instruction fetch at addr:%X\n", istate->lr);
  310.         }
  311.  
  312.     panic("Prefetch abourt ... solved");
  313. }
  314.  
  315. /** @}
  316.  */
  317.  
  318.