/**
* mini-HOWTO :
* 0) see where are MMU tables, and its size
* In the file *.map, look for ".MMU_tables", the address is given
* at the same line and looks like 0xa001f000. The size is given at
* the end of the same line.
* 1) get a memory dump file from this address
* Use BDI JTAG probe via telnet and type :
* dump
* Choose the file name you want. Note that this require that
* you have a properly configured TFTP server and BDI's configuration
* point on it.
* 2) launch decoder like this :
* ./decode_mmu_structs < mmu_dump_file
* where :
* - number of processes is : number of tasks + number of ISRs (cat 2.) + 1
* - number of page tables in a set : in the file *.map look for MMU_page_table_count, the address given before the name gives the value required here
* - base MMU table address : same address as given for the dump (in hexadecimal)
* do not forget to give the file via stdin using the "<" operator at the end of command line
*/
#include
#include
#include
/**
* type must be 1.
* See "ARM926EJ-S Technical Reference Manual" for
* more details.
*/
typedef struct {
unsigned int type : 2;
unsigned int unused1 : 2;
unsigned int must_be_one : 1;
unsigned int domain : 4;
unsigned int unused2 : 1;
unsigned int coarse_page_table_table_address : 22;
} MMU_coarse_page_table_descriptor;
/**
* type must be 2.
* See "ARM926EJ-S Technical Reference Manual" for
* more details.
*/
typedef struct {
unsigned int type : 2;
unsigned int buffered : 1;
unsigned int cacheable : 1;
unsigned int must_be_one : 1;
unsigned int domain : 4;
unsigned int must_be_zero1 : 1;
unsigned int access_permission : 2;
unsigned int must_be_zero2 : 8;
unsigned int section_base_address : 12;
} MMU_section_descriptor;
/**
* type must be 3.
* See "ARM926EJ-S Technical Reference Manual" for
* more details.
*/
typedef struct {
unsigned int type : 2;
unsigned int unused : 2;
unsigned int must_be_one : 1;
unsigned int domain : 4;
unsigned int must_be_zero : 3;
unsigned int fine_page_table_base_address : 20;
} MMU_fine_page_table_descriptor;
typedef union {
unsigned int raw;
MMU_coarse_page_table_descriptor coarse;
MMU_section_descriptor section;
MMU_fine_page_table_descriptor fine;
} MMU_first_level_descriptor;
typedef MMU_first_level_descriptor MMU_translation_table[4096];
typedef struct {
unsigned int type : 2;
unsigned int buffered : 1;
unsigned int cacheable : 1;
unsigned int access_permission_0 : 2;
unsigned int access_permission_1 : 2;
unsigned int access_permission_2 : 2;
unsigned int access_permission_3 : 2;
unsigned int unused : 4;
unsigned int page_base_address : 16;
} MMU_large_page_descriptor;
typedef struct {
unsigned int type : 2;
unsigned int buffered : 1;
unsigned int cacheable : 1;
unsigned int access_permission_0 : 2;
unsigned int access_permission_1 : 2;
unsigned int access_permission_2 : 2;
unsigned int access_permission_3 : 2;
unsigned int page_base_address : 20;
} MMU_small_page_descriptor;
typedef struct {
unsigned int type : 2;
unsigned int buffered : 1;
unsigned int cacheable : 1;
unsigned int access_permission : 2;
unsigned int unused : 4;
unsigned int page_base_address : 22;
} MMU_tiny_page_descriptor;
typedef union {
unsigned int raw;
MMU_large_page_descriptor large_page;
MMU_small_page_descriptor small_page;
MMU_tiny_page_descriptor tiny_page;
} MMU_second_level_descriptor;
typedef MMU_second_level_descriptor MMU_coarse_page_table[256];
typedef MMU_second_level_descriptor MMU_fine_page_table[1024];
#define AP_DECODE_STRING(AP) ((AP) == 1 ? "system only" : (AP) == 2 ? "read only" : (AP) == 3 ? "read/write" : "error")
unsigned char *MMU_data_buffer;
unsigned int MMU_data_base_address;
int number_of_processes;
int number_of_page_tables;
unsigned int get_page_table_address (int process, int page_table_number)
{
unsigned int ttables_size;
unsigned int page_table_offset;
ttables_size = number_of_processes * 4096 * 4;
page_table_offset = 4 * 1024 * (process * number_of_page_tables + page_table_number);
return MMU_data_base_address + ttables_size + page_table_offset;
}
#define PAGE_START(index) (0xA0000000 + (page_table_number << 20) + (index << 10))
#define PAGE_END(index) (0xA0000000 + (page_table_number << 20) + ((index + 1) << 10))
void decode_page_table (int process, int page_table_number)
{
MMU_second_level_descriptor *page_table;
MMU_second_level_descriptor previous_entry;
unsigned int ttables_size;
unsigned int page_table_offset;
unsigned int i;
unsigned int area_start, area_end;
unsigned int area_size;
ttables_size = number_of_processes * 4096 * 4;
page_table_offset = 4 * 1024 * (process * number_of_page_tables + page_table_number);
page_table = (MMU_second_level_descriptor *)(MMU_data_buffer + ttables_size + page_table_offset);
area_start = PAGE_START (0);
area_end = PAGE_END(0);
area_size = 1024;
previous_entry = page_table[0];
for (i = 1 ; i < 1023 ; i++)
{
if ((previous_entry.tiny_page.type == page_table[i].tiny_page.type) &&
(previous_entry.tiny_page.access_permission == page_table[i].tiny_page.access_permission))
{
area_end = PAGE_END(i);
area_size += 1024;
}
else
{
switch (previous_entry.tiny_page.type)
{
case 3:
printf (" [%4d KiB] 0x%08X -> 0x%08X : area with rights %s\n", area_size >> 10, area_start, area_end - 1,
AP_DECODE_STRING (previous_entry.tiny_page.access_permission));
break;
case 0:
printf (" [%4d KiB] 0x%08X -> 0x%08X : memory hole\n", area_size >> 10, area_start, area_end - 1);
break;
default:
printf (" error : page type = %d (related to memory area 0x%08X -> 0x%08X, page entry address : 0x%08X)\n", previous_entry.tiny_page.type,
area_start, area_end - 1,
get_page_table_address (process, page_table_number) + 4 * (i - 1));
exit (1);
}
/* restart new area */
area_start = PAGE_START(i);
area_end = PAGE_END(i);
area_size = 1024;
}
previous_entry = page_table[i];
}
area_end = PAGE_END(1023);
area_size += 1024;
switch (previous_entry.tiny_page.type)
{
case 3:
printf (" [%-4d KiB] 0x%08X -> 0x%08X : area with rights %s\n", area_size >> 10, area_start, area_end - 1,
AP_DECODE_STRING (previous_entry.tiny_page.access_permission));
break;
case 0:
printf (" [%-4d KiB] 0x%08X -> 0x%08X : memory hole\n", area_size >> 10, area_start, area_end - 1);
break;
default:
printf (" error : page type = %d (related to memory area 0x%08X -> 0x%08X, page entry address : 0x%08X)\n", previous_entry.tiny_page.type,
area_start, area_end - 1,
get_page_table_address (process, page_table_number) + 4 * (i - 1));
exit (1);
}
}
#define SECTION_START(index) ((index) << 20)
#define SECTION_END(index) (((index) + 1) << 20)
#define PAGE_INDEX(address) (((address) >> 20) - 0xA00)
void decode_mem_conf (int process)
{
int i;
MMU_first_level_descriptor *ttable;
MMU_first_level_descriptor previous_section;
unsigned int area_start, area_end;
unsigned int area_size;
unsigned int expected_pt_addr, read_pt_addr;
unsigned int current_page_index;
ttable = (MMU_first_level_descriptor*)(MMU_data_buffer + process * 4096 * 4);
area_start = SECTION_START (0);
area_end = SECTION_END (0);
area_size = 1024 * 1024;
previous_section = ttable[0];
for (i = 1 ; i < 4095 ; i++)
{
if ((previous_section.section.type == ttable[i].section.type))
{
area_end = SECTION_END(i);
area_size += 1024 * 1024;
}
else
{
/* show previous area */
switch (previous_section.section.type)
{
case 0:
printf ("[%4d MiB] 0x%08X -> 0x%08X : memory hole\n", area_size >> 20, area_start, area_end - 1);
break;
case 1:
printf ("[%4d MiB] 0x%08X -> 0x%08X : ERROR : coarse page table\n", area_size >> 20, area_start, area_end - 1);
break;
case 2:
printf ("[%4d MiB] 0x%08X -> 0x%08X : section with rights %s\n", area_size >> 20, area_start, area_end - 1,
AP_DECODE_STRING (previous_section.section.access_permission));
break;
case 3:
expected_pt_addr = get_page_table_address (process, (i - 1) - 0xA00);
read_pt_addr = previous_section.fine.fine_page_table_base_address << 12;
if (expected_pt_addr != read_pt_addr)
{
printf ("translation table does not give the right page table address (related memory area is 0x%08X -> 0x%08X)\n", area_start, area_end - 1);
printf ("expected 0x%08X, read 0x%08X\n", expected_pt_addr, read_pt_addr);
exit (1);
}
current_page_index = PAGE_INDEX(area_start);
do
{
printf (" ** page table @0x%08X\n", get_page_table_address (process, current_page_index));
decode_page_table (process, current_page_index);
current_page_index++;
}
while (current_page_index < PAGE_INDEX (area_end));
break;
default:
printf ("error : section type is invalid : type = %d, indice = %d\n", previous_section.section.type, i);
exit (1);
}
/* jump to next area */
area_start = SECTION_START(i);
area_end = SECTION_END(i);
area_size = 1024 * 1024;
}
previous_section = ttable[i];
}
area_end = SECTION_END(4095);
area_size += 1024 * 1024;
switch (previous_section.section.type)
{
case 0:
printf ("[%04d MiB] 0x%08X -> 0x%08X : memory hole\n", area_size >> 20, area_start, area_end - 1);
break;
case 1:
printf ("[%04d MiB] 0x%08X -> 0x%08X : ERROR : coarse page table\n", area_size >> 20, area_start, area_end - 1);
break;
case 2:
printf ("[%04d MiB] 0x%08X -> 0x%08X : section with rights %s\n", area_size >> 20, area_start, area_end - 1,
AP_DECODE_STRING (previous_section.section.access_permission));
break;
case 3:
if (get_page_table_address (process, i - 0xA00) != (ttable[i].fine.fine_page_table_base_address << 12))
{
printf ("translation table does not give the right page table address (related memory area is 0x%08X -> 0x%08X)\n", area_start, area_end - 1);
printf ("expected 0x%08X, read 0x%08X\n", get_page_table_address (process, i - 0xA00), ttable[i].fine.fine_page_table_base_address << 12);
exit (1);
}
current_page_index = PAGE_INDEX(area_start);
do
{
decode_page_table (process, current_page_index);
current_page_index++;
}
while (current_page_index < PAGE_INDEX (area_end));
break;
default:
printf ("error : section type is invalid : type = %d, indice = %d\n", previous_section.section.type, i);
exit (1);
}
}
int main (int argc, char**argv)
{
int i;
if (argc != 4)
{
printf ("Bad number of parameters (%d)\n", argc);
printf ("Usage : \n");
printf ("%s < mmu_data_dump_file\n", argv[0]);
exit (1);
}
number_of_processes = strtoll (argv[1], NULL, 10);
number_of_page_tables = strtoll (argv[2], NULL, 10);
MMU_data_base_address = strtoll (argv[3], NULL, 16);
assert (number_of_processes > 1);
assert (number_of_page_tables > 1);
assert ((MMU_data_base_address > 0xa0000000) && (MMU_data_base_address < 0xb0000000));
MMU_data_buffer = (unsigned char *)malloc (number_of_processes * 4 * (4096 + 1024 * number_of_page_tables));
while (!feof(stdin))
{
fread (MMU_data_buffer, 4 * (4096 + 1024 * number_of_page_tables), number_of_processes, stdin);
}
for (i = 0 ; i < number_of_processes ; i++)
{
printf ("--------------------------------------------\n");
printf ("Begin of memory protection map for process %d\n", i);
printf (" ** translation table @0x%08X\n", MMU_data_base_address + 4096 * 4 * i);
decode_mem_conf (i);
}
free (MMU_data_buffer);
return 0;
}