aboutsummaryrefslogtreecommitdiff
path: root/demo_functionality.c
blob: 53035b763fa2efc3450e98e007c261dac96487e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "uart.h"
#include "psr.h"
#include "memory.h"
#include "translation_table_descriptors.h"

void demo_paging_support(void)
{
  uint32_t ID_MMFR0;
  // get contents of coprocessor register to check for paging support
  asm("mrc p15, 0, %0, c0, c1, 4" : "=r" (ID_MMFR0));
  
  char *paging;
  
  switch(ID_MMFR0 & 0xf) /* lowest 4 bits indicate VMSA support */
    {
    case 0 : paging = "no paging\n\r"; break;
    case 1 : paging = "implementation defined paging\n\r"; break;
    case 2 : paging = "VMSAv6, with cache and TLB type registers\n\r"; break;
    case 3 : paging = "VMSAv7, with support for remapping and access flag\n\r"; break;
    case 4 : paging = "VMSAv7 with PXN bit supported\n\r"; break;
    case 5 : paging = "VMSAv7, PXN and long format descriptors. EPAE is supported.\n\r"; break;
    default : paging = "?_? unknown paging ?_?\n\r";
    }
  
  uart_puts(paging);
}

void demo_mode_to_system(void)
{

  // get content of current program status register to check the current
  // processor mode
  PSR_t CPSR = read_CPSR();

  char *mode_name;
  
  switch(CPSR.fields.PSR_MODE_4_0)
    {
    case MODE_USER       : mode_name = "User (PL0)\r\n"; break;
    case MODE_FIQ        : mode_name = "FIQ (PL1)\r\n"; break;
    case MODE_IRQ        : mode_name = "IRQ (PL1)\r\n"; break;
    case MODE_SUPERVISOR : mode_name = "Supervisor (PL1)\r\n"; break;
    case MODE_MONITOR    : mode_name = "Monitor (PL1)\r\n"; break;
    case MODE_ABORT      : mode_name = "Abort (PL1)\r\n"; break;
    case MODE_HYPERVISOR : mode_name = "Hyp (PL2)\r\n"; break;
    case MODE_UNDEFINED  : mode_name = "Undefined (PL1)\r\n"; break;
    case MODE_SYSTEM     : mode_name = "System (PL1)\r\n"; break;
    default : mode_name = "Unknown mode\r\n"; break;
    }

  uart_puts("current mode: ");
  uart_puts(mode_name);

  uart_puts("setting mode to system (PL1)...\r\n");
  set_system_mode();
}

extern char
  _binary_PL_0_test_img_start,
  _binary_PL_0_test_img_end,
  _binary_PL_0_test_img_size;

void demo_go_unprivileged(void)
{
  short_section_descriptor_t *translation_table =
    (short_section_descriptor_t*) TRANSLATION_TABLE_BASE;

  volatile short_section_descriptor_t *PL0_code_section =
    &translation_table[PL0_SECTION_NUMBER];
  volatile short_section_descriptor_t *UART_memory_section =
    &translation_table[((uint32_t) GPIO_BASE) >> 20];

  PL0_code_section->SECTION_BASE_ADDRESS_31_20 =
    UNPRIVILEGED_MEMORY_START >> 20;

  // make the selected section and uart section available for PL0
  PL0_code_section->ACCESS_PERMISSIONS_2   =
    AP_2_0_MODEL_RW_ALL >> 2;
  PL0_code_section->ACCESS_PERMISSIONS_1_0 =
    AP_2_0_MODEL_RW_ALL & 0b011;

  UART_memory_section->ACCESS_PERMISSIONS_2   =
    AP_2_0_MODEL_RW_ALL >> 2;
  UART_memory_section->ACCESS_PERMISSIONS_1_0 =
    AP_2_0_MODEL_RW_ALL & 0b011;
  

  // invalidate main Translation Lookup Buffer (just in case)
  asm("mcr p15, 0, %0, c8, c7, 0\n\r"
      "isb" :: "r" (0) : "memory");
  
  // check that translation works... by copying a string using one
  // mapping and reading it using other :D
  char message[] = "mapped sections for PL0 code\n\r";
  
  unsigned int i;
  for (i = 0; i < sizeof(message); i++)
    ((volatile char*) UNPRIVILEGED_MEMORY_START)[i] = message[i];
  
  uart_puts((char*) VIRTUAL_PL0_MEMORY_START);

  // now paste a userspace program to that section, jump to it and
  // switch to PL0
  for (size_t i = 0; i < (size_t) &_binary_PL_0_test_img_size; i++)
    ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] =
      (&_binary_PL_0_test_img_start)[i];

  // jump to that copied code (switch to PL0 is done by that code)
  asm volatile("mov  r5, #0\n\r"
  	       "movt r5, #"PL0_SECTION_NUMBER_STR"1111\n\r"
  	       "mov  sp, r5\n\r" // setting stack is important :D
  	       "mov  r5, #0\n\r"
  	       "movt r5, #"PL0_SECTION_NUMBER_STR"0000\n\r"
  	       "blx  r5\n\r");
}