Subversion Repositories HelenOS

Rev

Rev 2263 | 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. #include <arch/debug_print/print.h>
  46.  
  47.  
  48. // localy used types
  49. /**
  50.  * Decribes structure of fault status register in coprocessor 15
  51.  */
  52. typedef struct {
  53.         unsigned status              : 3;
  54.         unsigned domain              : 4;
  55.         unsigned zero            : 1;
  56.         unsigned should_be_zero      : 24;
  57. } __attribute__ ((packed)) fault_status_t;
  58.  
  59. /**
  60.  * Help union used for overcasting integer value into fault_status_t type
  61.  */
  62. typedef union {
  63.     fault_status_t  fsr;
  64.     uint32_t    dummy;
  65. } fault_status_union_t;
  66.  
  67. /**
  68.  * Very simplyfied description of instruction code structure intended for
  69.  * recognising memmory access of instruction ( reads or writes into memmory)
  70.  * more details: see ARM architecture preference chapter:3.1 Instruction set encoding
  71.  */
  72. typedef struct {
  73.         unsigned dummy1              : 4;
  74.         unsigned bit4                : 1;
  75.         unsigned bits567             : 3;
  76.         unsigned dummy               : 12;
  77.         unsigned access              : 1;
  78.         unsigned opcode              : 4;
  79.         unsigned instr_type          : 3;
  80.         unsigned condition       : 4;
  81. } __attribute__ ((packed)) instruction_t;
  82.  
  83. /**
  84.  *  Help union used for overcasting ip register (uint_32_t) value into instruction_t pointer
  85.  */
  86. typedef union {
  87.     instruction_t*  instr;
  88.     uint32_t    ip;
  89. } instruction_union_t;
  90.  
  91. // localy used functions
  92. static fault_status_t read_fault_status_register();
  93. static uintptr_t read_fault_address_register();
  94. static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr);
  95.  
  96.  
  97. /**
  98.  * Initializes kernel adress space page tables, sets abourts exceptions vectors
  99.  */
  100. void page_arch_init(void)
  101. {
  102.     uintptr_t cur;
  103.     int flags;
  104.  
  105.     page_mapping_operations = &pt_mapping_operations;
  106.  
  107.     flags = PAGE_CACHEABLE;
  108.  
  109.     /* PA2KA(identity) mapping for all frames until last_frame */
  110.     for (cur = 0; cur < last_frame; cur += FRAME_SIZE) {
  111.         page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags);
  112.     }
  113.  
  114.     // TODO: move to the kernel space
  115.     page_mapping_insert(AS_KERNEL, 0x00000000, 0x00000000, flags);
  116.     // TODO: remove when aux_printf not needed
  117.     page_mapping_insert(AS_KERNEL, 0x10000000, 0x10000000, flags);
  118.  
  119.     exc_register(EXC_DATA_ABORT,     "page_fault data abort",     (iroutine) data_abourt);
  120.     exc_register(EXC_PREFETCH_ABORT, "page_fault prefetch abort", (iroutine) prefetch_abourt);
  121.  
  122.     as_switch(NULL, AS_KERNEL);
  123.  
  124.     // TODO: register fault routine
  125. }
  126.  
  127. /**
  128.  * Map device into kernel space.
  129.  *
  130.  * This function adds mapping of physical address that is read/write only
  131.  *  from kernel and not bufferable.
  132.  *
  133.  * \param physaddr Physical addres where device is connected
  134.  * \param size Length of area where device is present
  135.  * \return Virtual address where device will be accessable
  136.  * Note: This is copy of IA32 hw_map code
  137.  */
  138. uintptr_t hw_map(uintptr_t physaddr, size_t size)
  139. {
  140.     if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
  141.         panic("Unable to map physical memory %p (%d bytes)", physaddr, size)
  142.  
  143.     uintptr_t virtaddr = PA2KA(last_frame);
  144.     pfn_t i;
  145.     for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++)
  146.         page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), physaddr + PFN2ADDR(i), PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL);
  147.  
  148.     last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
  149.  
  150.     return virtaddr;
  151. }
  152.  
  153. //TODO: remove in final version
  154. static void print_istate(istate_t* istate);
  155. static void print_istate(istate_t* istate) {
  156.  dprintf("\nIstate dump:\n");
  157.  dprintf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
  158.  dprintf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
  159.  dprintf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
  160.  dprintf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
  161. }
  162.  
  163. /**
  164.  * \return Value stored in fault status register
  165.  */
  166. static fault_status_t read_fault_status_register() {
  167.         fault_status_union_t tmp;
  168.         asm volatile (
  169.         "mrc p15, 0, %0, c5, c0, 0"
  170.             : "=r"(tmp.dummy)
  171.     );
  172.     return tmp.fsr;
  173. }
  174.  
  175. /**
  176.  * \return Virtual adress. Access on this addres caused exception
  177.  */
  178. static uintptr_t read_fault_address_register() {
  179.         uintptr_t tmp;
  180.     // Fault adress is stored in coprocessor15, register 6
  181.     asm volatile (
  182.         "mrc p15, 0, %0, c6, c0, 0"
  183.         : "=r"(tmp)
  184.     );
  185.     return tmp;
  186. };
  187.  
  188. /**
  189.  * Decode instruction and decide if try to read or write into memmory.
  190.  *
  191.  * \param instr_addr address of instruction which attempts to access into memmory
  192.  * \param badvaddr Virtual address on which instruction tries to access
  193.  * \return type of access into memmory
  194.  *  Note: return PF_ACESS_EXEC if no memmory acess
  195.  */
  196. //TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
  197. pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
  198.         instruction_union_t tmp;
  199.         tmp.ip = instr_addr;
  200.     // get instruction op code
  201.     instruction_t i_code = *(tmp.instr);
  202.  
  203.         dprintf("get_instruction_memmory_access\n");
  204.     dprintf(" i_code:%X\n",i_code);
  205.     dprintf(" i_code.condition:%d\n", i_code.condition);
  206.     dprintf(" i_code.instr_type:%d\n",i_code.instr_type);
  207.     dprintf(" i_code.opcode:%d\n",i_code.opcode);
  208.     dprintf(" i_code.acess:%d\n", i_code.access);
  209.     dprintf(" i_code.dummy:%d\n", i_code.dummy);
  210.     dprintf(" i_code.bits567%d\n", i_code.bits567);
  211.     dprintf(" i_code.bit4:%d\n", i_code.bit4);
  212.     dprintf(" i_code.dummy1:%d\n", i_code.dummy1);
  213.  
  214.  
  215.         // undefined instructions ... (or special instructions)
  216.     if ( i_code.condition == 0xf ) {
  217.         panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  218.         return PF_ACCESS_EXEC;
  219.     }
  220.  
  221.     // load store instructions
  222.         if ( ( i_code.instr_type == 0x2 ) || // load store immediate offset
  223.              ( i_code.instr_type == 0x3 && i_code.bit4 == 0) || // load store register offset
  224.              ( i_code.instr_type == 0x4 ) || // load store multiple
  225.          ( i_code.instr_type == 0x6 )    // coprocessor load / strore
  226.        ) {
  227.         if ( i_code.access == 1) {
  228.             return PF_ACCESS_READ;
  229.         } else {
  230.             return PF_ACCESS_WRITE;
  231.         }
  232.     };
  233.  
  234.     // swap, swpb instruction
  235.     if ( i_code.instr_type == 0x0 && (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
  236.          i_code.access == 0x0 && i_code.bits567 == 0x4 && i_code.bit4 == 1 )
  237.      {
  238.         /* Swap instructions make read and write in one step.
  239.          * Type of access that caused exception have to page tables and access rights.
  240.          */
  241. //TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
  242. //      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
  243. //  same case as_page_fault .... it's nessesary to solve "stack" problem
  244.                 pte_level1_t* pte = (pte_level1_t*)pt_mapping_operations.mapping_find(AS, badvaddr);
  245.  
  246.         ASSERT(pte);
  247.  
  248.                 /* check if read possible
  249.                  * Note: Don't check PTE_READABLE because it returns 1 everytimes */
  250.         if ( !PTE_PRESENT(pte) ) {
  251.                 return PF_ACCESS_READ;
  252.         }
  253.         if ( !PTE_WRITABLE(pte) ) {
  254.             return PF_ACCESS_WRITE;
  255.         }
  256.         else
  257.             // badvaddr is present readable and writeable but error occured ... why?
  258.             panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  259.     }
  260.     panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  261.     return PF_ACCESS_EXEC;
  262. }
  263.  
  264. /**
  265.  * Routine that solves exception data_abourt
  266.  *  ... you try to load or store value into invalid memmory address
  267.  * \param istate State of CPU when data abourt occured
  268.  * \param n number of exception
  269.  */
  270. //TODO: remove debug prints in final tested version
  271. void data_abourt(int n, istate_t *istate) {
  272.         fault_status_t fsr = read_fault_status_register();
  273.         uintptr_t  page = read_fault_address_register();
  274.  
  275.     pf_access_t access = get_memmory_access_type( istate->lr, page);
  276.  
  277.     print_istate(istate);
  278.     dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access);
  279.  
  280.         int ret = as_page_fault(page, access, istate);
  281.     dprintf(" as_page_fault ret:%d\n", ret);
  282.         if (ret == AS_PF_FAULT) {
  283.         fault_if_from_uspace(istate, "Page fault: %#x", page);
  284.  
  285.                 panic("page fault\n");
  286.         }
  287.  
  288.     // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
  289.     panic("page fault ... solved\n");
  290.  
  291. }
  292.  
  293. /**
  294.  * Routine that solves exception prefetch_about
  295.  *  ... you try to execute instruction on invalid address
  296.  * \param istate State of CPU when prefetch abourt occured
  297.  * \param n number of exception
  298.  */
  299. void prefetch_abourt(int n, istate_t *istate) {
  300.  // Prefetch can be made be bkpt instruction
  301.     print_istate(istate);
  302.     dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr);
  303.  
  304.         int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate);
  305.     dprintf(" as_page_fault ret:%d\n", ret);
  306.         if (ret == AS_PF_FAULT) {
  307.                 panic("page fault - instruction fetch at addr:%X\n", istate->lr);
  308.         }
  309.  
  310.     panic("Prefetch abourt ... solved");
  311. }
  312.  
  313. /** @}
  314.  */
  315.  
  316.