Subversion Repositories HelenOS

Rev

Rev 2256 | 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.     page_mapping_insert(AS_KERNEL, 0x10000000, 0x10000000, flags);
  119.     page_mapping_insert(AS_KERNEL, 0x15000000, 0x15000000, flags);
  120.     page_mapping_insert(AS_KERNEL, 0x16000000, 0x16000000, flags);
  121.  
  122.  
  123.         exc_register(EXC_DATA_ABORT,     "page_fault data abort",     (iroutine) data_abourt);
  124.         exc_register(EXC_PREFETCH_ABORT, "page_fault prefetch abort", (iroutine) prefetch_abourt);
  125.  
  126.     /* Sets mapping to kernel mapping. It's nessesary to hw_map changes take place immediately
  127.      * after hw_map function is called. */
  128.     as_switch( NULL, AS_KERNEL);
  129.  
  130.     // note for Alf: kernel part of page table is copied in generic/mm/as_pt.c/ptl0_create
  131.     // TODO: register fault routine
  132. }
  133.  
  134. /**
  135.  * Map device into kernel space.
  136.  *
  137.  * This function adds mapping of physical address that is read/write only
  138.  *  from kernel and not bufferable.
  139.  *
  140.  * \param physaddr Physical addres where device is connected
  141.  * \param size Length of area where device is present
  142.  * \return Virtual address where device will be accessable
  143.  * Note: This is copy of IA32 hw_map code
  144.  */
  145. uintptr_t hw_map(uintptr_t physaddr, size_t size)
  146. {
  147.     if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
  148.         panic("Unable to map physical memory %p (%d bytes)", physaddr, size)
  149.  
  150.     uintptr_t virtaddr = PA2KA(last_frame);
  151.     pfn_t i;
  152.     for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++)
  153.         page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), physaddr + PFN2ADDR(i), PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL);
  154.  
  155.     last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
  156.  
  157.     return virtaddr;
  158. }
  159.  
  160. //TODO: remove in final version
  161. static void print_istate(istate_t* istate);
  162. static void print_istate(istate_t* istate) {
  163.  aux_printf("\nIstate dump:\n");
  164.  aux_printf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
  165.  aux_printf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
  166.  aux_printf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
  167.  aux_printf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
  168. }
  169.  
  170. /**
  171.  * \return Value stored in fault status register
  172.  */
  173. static fault_status_t read_fault_status_register() {
  174.         fault_status_union_t tmp;
  175.         asm volatile (
  176.         "mrc p15, 0, %0, c5, c0, 0"
  177.             : "=r"(tmp.dummy)
  178.     );
  179.     return tmp.fsr;
  180. }
  181.  
  182. /**
  183.  * \return Virtual adress. Access on this addres caused exception
  184.  */
  185. static uintptr_t read_fault_address_register() {
  186.         uintptr_t tmp;
  187.     // Fault adress is stored in coprocessor15, register 6
  188.     asm volatile (
  189.         "mrc p15, 0, %0, c6, c0, 0"
  190.         : "=r"(tmp)
  191.     );
  192.     return tmp;
  193. };
  194.  
  195. /**
  196.  * Decode instruction and decide if try to read or write into memmory.
  197.  *
  198.  * \param instr_addr address of instruction which attempts to access into memmory
  199.  * \param badvaddr Virtual address on which instruction tries to access
  200.  * \return type of access into memmory
  201.  *  Note: return PF_ACESS_EXEC if no memmory acess
  202.  */
  203. //TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
  204. pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
  205.         instruction_union_t tmp;
  206.         tmp.ip = instr_addr;
  207.     // get instruction op code
  208.     instruction_t i_code = *(tmp.instr);
  209.  
  210.         aux_printf("get_instruction_memmory_access\n");
  211.     aux_printf(" i_code:%X\n",i_code);
  212.     aux_printf(" i_code.condition:%d\n", i_code.condition);
  213.     aux_printf(" i_code.instr_type:%d\n",i_code.instr_type);
  214.     aux_printf(" i_code.opcode:%d\n",i_code.opcode);
  215.     aux_printf(" i_code.acess:%d\n", i_code.access);
  216.     aux_printf(" i_code.dummy:%d\n", i_code.dummy);
  217.     aux_printf(" i_code.bits567%d\n", i_code.bits567);
  218.     aux_printf(" i_code.bit4:%d\n", i_code.bit4);
  219.     aux_printf(" i_code.dummy1:%d\n", i_code.dummy1);
  220.  
  221.  
  222.         // undefined instructions ... (or special instructions)
  223.     if ( i_code.condition == 0xf ) {
  224.         panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  225.         return PF_ACCESS_EXEC;
  226.     }
  227.  
  228.     // load store instructions
  229.         if ( ( i_code.instr_type == 0x2 ) || // load store immediate offset
  230.              ( i_code.instr_type == 0x3 && i_code.bit4 == 0) || // load store register offset
  231.              ( i_code.instr_type == 0x4 ) || // load store multiple
  232.          ( i_code.instr_type == 0x6 )    // coprocessor load / strore
  233.        ) {
  234.         if ( i_code.access == 1) {
  235.             return PF_ACCESS_READ;
  236.         } else {
  237.             return PF_ACCESS_WRITE;
  238.         }
  239.     };
  240.  
  241.     // swap, swpb instruction
  242.     if ( i_code.instr_type == 0x0 && (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
  243.          i_code.access == 0x0 && i_code.bits567 == 0x4 && i_code.bit4 == 1 )
  244.      {
  245.         /* Swap instructions make read and write in one step.
  246.          * Type of access that caused exception have to page tables and access rights.
  247.          */
  248. //TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
  249. //      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
  250. //  same case as_page_fault .... it's nessesary to solve "stack" problem
  251.                 pte_level1_t* pte = (pte_level1_t*)pt_mapping_operations.mapping_find(AS, badvaddr);
  252.  
  253.         ASSERT(pte);
  254.  
  255.                 /* check if read possible
  256.                  * Note: Don't check PTE_READABLE because it returns 1 everytimes */
  257.         if ( !PTE_PRESENT(pte) ) {
  258.                 return PF_ACCESS_READ;
  259.         }
  260.         if ( !PTE_WRITABLE(pte) ) {
  261.             return PF_ACCESS_WRITE;
  262.         }
  263.         else
  264.             // badvaddr is present readable and writeable but error occured ... why?
  265.             panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  266.     }
  267.     panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
  268.     return PF_ACCESS_EXEC;
  269. }
  270.  
  271. /**
  272.  * Routine that solves exception data_abourt
  273.  *  ... you try to load or store value into invalid memmory address
  274.  * \param istate State of CPU when data abourt occured
  275.  * \param n number of exception
  276.  */
  277. //TODO: remove debug prints in final tested version
  278. void data_abourt(int n, istate_t *istate) {
  279.         fault_status_t fsr = read_fault_status_register();
  280.         uintptr_t  page = read_fault_address_register();
  281.  
  282.     pf_access_t access = get_memmory_access_type( istate->lr, page);
  283.  
  284.     print_istate(istate);
  285.     aux_printf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access);
  286.  
  287.         int ret = as_page_fault(page, access, istate);
  288.     aux_printf(" as_page_fault ret:%d\n", ret);
  289.         if (ret == AS_PF_FAULT) {
  290.         fault_if_from_uspace(istate, "Page fault: %#x", page);
  291.  
  292.                 panic("page fault\n");
  293.         }
  294.  
  295.     // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
  296.     panic("page fault ... solved\n");
  297.  
  298. }
  299.  
  300. /**
  301.  * Routine that solves exception prefetch_about
  302.  *  ... you try to execute instruction on invalid address
  303.  * \param istate State of CPU when prefetch abourt occured
  304.  * \param n number of exception
  305.  */
  306. void prefetch_abourt(int n, istate_t *istate) {
  307.  // Prefetch can be made be bkpt instruction
  308.     print_istate(istate);
  309.     aux_printf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr);
  310.  
  311.         int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate);
  312.     aux_printf(" as_page_fault ret:%d\n", ret);
  313.         if (ret == AS_PF_FAULT) {
  314.                 panic("page fault - instruction fetch at addr:%X\n", istate->lr);
  315.         }
  316.  
  317.     panic("Prefetch abourt ... solved");
  318. }
  319.  
  320. /** @}
  321.  */
  322.  
  323.