aboutsummaryrefslogtreecommitdiff
path: root/demo_functionality.c
blob: 4b002d6b083d436e0415a652328ec02ca6c2a7f2 (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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include "uart.h"
#include "psr.h"
#include "memory.h"
#include "translation_table_descriptors.h"
#include "ramfs.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_current_mode(void)
{

  // get content of current program status register to check the current
  // processor mode (should be system, as we set it in boot.S)
  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);
}

#define TRANSLATION_TABLE						\
  ((short_section_descriptor_t volatile*) TRANSLATION_TABLE_BASE)

extern char
  _binary_ramfs_img_start,
  _binary_ramfs_img_end,
  _binary_ramfs_img_size;

void demo_setup_PL0(void)
{
  // find PL_0_test.img im ramfs
  struct ramfile PL_0_test_img;

  if (find_file(&_binary_ramfs_img_start, "PL_0_test.img",
		&PL_0_test_img))
    {
      uart_puts("PL_0_test.img not found :(\r\n");
      asm volatile ("wfi");
    }

  short_section_descriptor_t volatile *PL0_section_entry =
    &TRANSLATION_TABLE[PL0_SECTION_NUMBER];
  short_section_descriptor_t volatile *UART_memory_section_entry =
    &TRANSLATION_TABLE[((uint32_t) GPIO_BASE) >> 20];

  short_section_descriptor_t
    PL0_section = *PL0_section_entry,
    UART_memory_section = *UART_memory_section_entry;

  // set up address of PL0 section
  PL0_section.SECTION_BASE_ADDRESS_31_20 =
    UNPRIVILEGED_MEMORY_START >> 20;

  // make the selected section and uart section available for PL0
  PL0_section.ACCESS_PERMISSIONS_2 =
    AP_2_0_MODEL_RW_ALL >> 2;
  PL0_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;

  *PL0_section_entry = PL0_section;
  *UART_memory_section_entry = UART_memory_section;

  // 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
  for (uint32_t i = 0; i < PL_0_test_img.file_size; i++)
    ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] =
      PL_0_test_img.file_contents[i];

  uart_puts("copied PL0 code to it's section\n\r");
}

// needed for array initialization in demo_go_unprivileged()
void *memset(void *s, int c, size_t n)
{
  char *mem = s;
  
  for (size_t i = 0; i < n; i++)
    mem[i] = c;
  
  return s;
}

void demo_go_unprivileged(void)
{
  uint32_t PL0_regs[16] = {0};
  PL0_regs[15] = VIRTUAL_PL0_MEMORY_START;       // the new pc
  PL0_regs[13] = (PL0_SECTION_NUMBER + 1) << 20; // the new sp

  PSR_t new_SPSR = read_CPSR();
  new_SPSR.fields.PSR_MODE_4_0 = MODE_USER;
  write_SPSR(new_SPSR);

  uart_puts("All ready, jumping to PL0 code\n\r");
  
  asm volatile("ldm %0, {r0 - r15} ^" ::
	       "r" (PL0_regs));
}

extern char
  __interrupts_start,
  __interrupts_end,
  __interrupts_size;

extern void (*volatile system_reentry_point)(void);

void system_reentry(void)
{
  uart_puts("re-entered system");
  while(1);
}

void demo_setup_interrupts(void)
{
  system_reentry_point = system_reentry;

  for (size_t i = 0; i < (size_t) &__interrupts_size; i++)
    ((volatile char*) 0)[i] =
      (&__interrupts_start)[i];
}