Theory MMU

(*  Title:     Memory.thy
    Author:    David Sanán, Trinity College Dublin, 2012
               Zhe Hou, NTU, 2016.
*)


section ‹Memory Management Unit (MMU)›

theory MMU
imports Main RegistersOps Sparc_Types
begin

section ‹MMU  Sizing› 

text‹
  We need some citation here for documentation about the MMU.
›
text‹The MMU uses the Address Space Identifiers (ASI) to control memory access.
ASI = 8, 10 are for user; ASI = 9, 11 are for supervisor.›

subsection "MMU Types"

type_synonym word_PTE_flags = word8
type_synonym word_length_PTE_flags = word_length8

subsection "MMU length values"

text‹Definitions for the length of the virtua address, page size,  
virtual translation tables indexes, virtual address offset and Page protection flags›


definition length_entry_type :: "nat" 
where "length_entry_type  LENGTH(word_length_entry_type)" 
definition length_phys_address:: "nat" 
where "length_phys_address  LENGTH(word_length_phys_address)"
definition length_virtua_address:: "nat" 
where "length_virtua_address  LENGTH(word_length_virtua_address)"
definition length_page:: "nat" where "length_page  LENGTH(word_length_page)"
definition length_t1:: "nat" where "length_t1  LENGTH(word_length_t1)"
definition length_t2:: "nat" where "length_t2  LENGTH(word_length_t2)"
definition length_t3:: "nat" where "length_t3  LENGTH(word_length_t3)"
definition length_offset:: "nat" where "length_offset  LENGTH(word_length_offset)"
definition length_PTE_flags :: "nat" where 
"length_PTE_flags  LENGTH(word_length_PTE_flags)"

subsection "MMU index values"

definition va_t1_index :: "nat" where "va_t1_index  length_virtua_address - length_t1"
definition va_t2_index :: "nat" where "va_t2_index  va_t1_index - length_t2"
definition va_t3_index :: "nat" where "va_t3_index  va_t2_index - length_t3"
definition va_offset_index :: "nat" where "va_offset_index  va_t3_index - length_offset"
definition pa_page_index :: "nat" 
where "pa_page_index  length_phys_address - length_page"
definition pa_offset_index :: "nat" where 
"pa_offset_index  pa_page_index -length_page"

section ‹MMU Definition›

record MMU_state =
   registers :: "MMU_context"
(*   contexts:: context_table*)

text ‹The following functions access MMU registers via addresses. 
  See UT699LEON3FT manual page 35.›

definition mmu_reg_val:: "MMU_state  virtua_address  machine_word option"
where "mmu_reg_val mmu_state addr 
  if addr = 0x000 then ― ‹MMU control register›
    Some ((registers mmu_state) CR)
  else if addr = 0x100 then ― ‹Context pointer register›
    Some ((registers mmu_state) CTP)
  else if addr = 0x200 then ― ‹Context register›
    Some ((registers mmu_state) CNR)
  else if addr = 0x300 then ― ‹Fault status register›
    Some ((registers mmu_state) FTSR)
  else if addr = 0x400 then ― ‹Fault address register›
    Some ((registers mmu_state) FAR)
  else None"

definition mmu_reg_mod:: "MMU_state  virtua_address  machine_word 
  MMU_state option" where
"mmu_reg_mod mmu_state addr w 
  if addr = 0x000 then ― ‹MMU control register›
    Some (mmu_stateregisters := (registers mmu_state)(CR := w))
  else if addr = 0x100 then ― ‹Context pointer register›
    Some (mmu_stateregisters := (registers mmu_state)(CTP := w))
  else if addr = 0x200 then ― ‹Context register›
    Some (mmu_stateregisters := (registers mmu_state)(CNR := w))
  else if addr = 0x300 then ― ‹Fault status register›
    Some (mmu_stateregisters := (registers mmu_state)(FTSR := w))
  else if addr = 0x400 then ― ‹Fault address register›
    Some (mmu_stateregisters := (registers mmu_state)(FAR := w))
  else None"

section ‹Virtual Memory›

subsection ‹MMU Auxiliary Definitions›

definition getCTPVal:: "MMU_state  machine_word"
where "getCTPVal mmu   (registers mmu) CTP"

definition getCNRVal::"MMU_state  machine_word"
where "getCNRVal mmu   (registers mmu) CNR"


text‹
 The physical context table address is got from the ConText Pointer register (CTP) and the 
Context Register (CNR) MMU registers. 
 The CTP is shifted to align it with 
the physical address (36 bits) and we add the table index given on CNR.
CTP is right shifted 2 bits, cast to phys address and left shifted 6 bytes 
to be aligned with the context register.  
CNR is 2 bits left shifted for alignment with the context table.
›

definition compose_context_table_addr :: "machine_word machine_word 
                                           phys_address"
where 
 "compose_context_table_addr ctp cnr 
     ((ucast (ctp >> 2)) << 6) + (ucast cnr << 2)"

subsection ‹Virtual Address Translation›

text‹Get the context table phys address from the MMU registers›
definition get_context_table_addr :: "MMU_state  phys_address"
where 
 "get_context_table_addr mmu 
      compose_context_table_addr (getCTPVal mmu) (getCNRVal mmu)"

definition va_list_index :: "nat list" where
"va_list_index  [va_t1_index,va_t2_index,va_t3_index,0]"

definition offset_index :: "nat list" where
"offset_index 
   [ length_machine_word
    , length_machine_word-length_t1
    , length_machine_word-length_t1-length_t2
    , length_machine_word-length_t1-length_t2-length_t3
    ]"

definition index_len_table :: "nat list" where "index_len_table  [8,6,6,0]"

definition n_context_tables :: "nat" where "n_context_tables  3"

text ‹The following are basic physical memory read functions. 
At this level we don't need the write memory yet.›

definition mem_context_val:: "asi_type  phys_address  
                      mem_context  mem_val_type option"
where
"mem_context_val asi add m  
  let asi8 = word_of_int 8;
      r1 = m asi add 
  in
  if r1 = None then
    m asi8 add
  else r1
"

context
  includes bit_operations_syntax
begin

text ‹Given an ASI (word8), an address (word32) addr, 
        read the 32bit value from the memory addresses 
        starting from address addr' where addr' = addr 
        exception that the last two bits are 0's. 
        That is, read the data from 
        addr', addr'+1, addr'+2, addr'+3.›
definition mem_context_val_w32 :: "asi_type  phys_address  
                           mem_context  word32 option"
where
"mem_context_val_w32 asi addr m 
  let addr' = (AND) addr 0b111111111111111111111111111111111100;
      addr0 = (OR) addr' 0b000000000000000000000000000000000000;
      addr1 = (OR) addr' 0b000000000000000000000000000000000001;
      addr2 = (OR) addr' 0b000000000000000000000000000000000010;
      addr3 = (OR) addr' 0b000000000000000000000000000000000011;
      r0 = mem_context_val asi addr0 m;
      r1 = mem_context_val asi addr1 m;
      r2 = mem_context_val asi addr2 m;
      r3 = mem_context_val asi addr3 m
  in
  if r0 = None  r1 = None  r2 = None  r3 = None then
    None
  else
    let byte0 = case r0 of Some v  v;
        byte1 = case r1 of Some v  v;
        byte2 = case r2 of Some v  v;
        byte3 = case r3 of Some v  v 
    in
    Some ((OR) ((OR) ((OR) ((ucast(byte0)) << 24) 
                              ((ucast(byte1)) << 16)) 
                       ((ucast(byte2)) << 8)) 
                (ucast(byte3)))
"

text @{term "get_addr_from_table"} browses the page description tables  
  until it finds a PTE (bits==suc (suc 0).

  If it is a PTE it aligns the 24 most significant bits of the entry
  with the most significant bits of the phys address and or-ed with the offset,
   which will vary depending on the entry level. 
 In the case we are looking at the last table level (level 3),
   the offset is aligned to 0 otherwise it will be 2.
  
 If the table entry is a PTD (bits== Suc 0),
  the index is obtained from the virtual address depending on the current level and or-ed with the PTD. 
›

function ptd_lookup:: "virtua_address  virtua_address 
mem_context  nat  (phys_address × PTE_flags) option" 
where "ptd_lookup va pt m lvl = (
  if lvl > 3 then None
  else 
    let thislvl_offset = (
      if lvl = 1 then (ucast ((ucast (va >> 24))::word8))::word32
      else if lvl = 2 then (ucast ((ucast (va >> 18))::word6))::word32
      else (ucast ((ucast (va >> 12))::word6))::word32);
        thislvl_addr = (OR) pt thislvl_offset;
        thislvl_data = mem_context_val_w32 (word_of_int 9) (ucast thislvl_addr) m
    in
    case thislvl_data of 
    Some v  (
      let et_val = (AND) v 0b00000000000000000000000000000011 in
      if et_val = 0 then ― ‹Invalid›
        None
      else if et_val = 1 then ― ‹Page Table Descriptor›
        let ptp = (AND) v 0b11111111111111111111111111111100 in
        ptd_lookup va ptp m (lvl+1)
      else if et_val = 2 then ― ‹Page Table Entry›
        let ppn = (ucast (v >> 8))::word24;
            va_offset = (ucast ((ucast va)::word12))::word36
        in
        Some (((OR) (((ucast ppn)::word36) << 12) va_offset), 
              ((ucast v)::word8))
      else ― ‹et_val = 3›, reserved.›
        None
    )
    |None  None)
"
by pat_completeness auto
termination  
by (relation "measure (λ (va, (pt, (m, lvl))). 4 - lvl)") auto

definition get_acc_flag:: "PTE_flags  word3" where
"get_acc_flag w8  (ucast (w8 >> 2))::word3"

definition mmu_readable:: "word3  asi_type  bool" where
"mmu_readable f asi 
  if uint asi  {8, 10} then
    if uint f  {0,1,2,3,5} then True
    else False
  else if uint asi  {9, 11} then
    if uint f  {0,1,2,3,5,6,7} then True
    else False
  else False
"

definition mmu_writable:: "word3  asi_type  bool" where
"mmu_writable f asi 
  if uint asi  {8, 10} then
    if uint f  {1,3} then True
    else False
  else if uint asi  {9, 11} then
    if uint f  {1,3,5,7} then True
    else False
  else False
"

definition virt_to_phys :: "virtua_address  MMU_state   mem_context  
                            (phys_address × PTE_flags) option"
where 
 "virt_to_phys va mmu m  
    let ctp_val = mmu_reg_val mmu (0x100);
        cnr_val = mmu_reg_val mmu (0x200);
        mmu_cr_val = (registers mmu) CR
    in
    if (AND) mmu_cr_val 1  0 then ― ‹MMU enabled.›
      case (ctp_val,cnr_val) of
      (Some v1, Some v2) 
        let context_table_entry = (OR) ((v1 >> 11) << 11)
            (((AND) v2 0b00000000000000000000000111111111) << 2);
            context_table_data = mem_context_val_w32 (word_of_int 9) 
              (ucast context_table_entry) m
        in (
        case context_table_data of
        Some lvl1_page_table 
          ptd_lookup va lvl1_page_table m 1
        |None  None)
      |_  None
    else Some ((ucast va), ((0b11101111)::word8)) 
"

text ‹
\newpage

The below function gives the initial values of MMU registers.
In particular, the MMU context register CR is 0 because:
We don't know the bits for IMPL, VER, and SC;
the bits for PSO are 0s because we use TSO;
the reserved bits are 0s;
we assume NF bits are 0s;
and most importantly, the E bit is 0 because when the machine 
starts up, MMU is disabled. 
An initial boot procedure (bootloader or something like that) should 
configure the MMU and then enable it if the OS uses MMU.›

definition MMU_registers_init :: "MMU_context"
where "MMU_registers_init r  0" 

definition mmu_setup :: "MMU_state"
where "mmu_setup  registers=MMU_registers_init"

end

end