81734e0c1dbf59eaab2a259f0dd3576a1d7554fc
[fw/openocd] / src / target / nds32_tlb.c
1 /***************************************************************************
2  *   Copyright (C) 2013 Andes Technology                                   *
3  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
17  ***************************************************************************/
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "nds32_aice.h"
23 #include "nds32_tlb.h"
24
25 int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address,
26                 target_addr_t *physical_address)
27 {
28         struct target *target = nds32->target;
29         struct aice_port_s *aice = target_to_aice(target);
30
31         return aice_read_tlb(aice, virtual_address, physical_address);
32 }
33
34 static struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = {
35         /* 4K page */
36         {0xFFC00000, 20, 0x003FF000, 10, 0x00000FFF, 0xFFFFF000, 0xFFFFF000, 0xFFFFF000},
37         /* 8K page */
38         {0xFF000000, 22, 0x00FFE000, 11, 0x00001FFF, 0xFFFFF000, 0xFFFFE000, 0xFFFFE000},
39 };
40
41 int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address,
42                 target_addr_t *physical_address)
43 {
44         struct target *target = nds32->target;
45         uint32_t value_mr1;
46         uint32_t load_address;
47         uint32_t l1_page_table_entry;
48         uint32_t l2_page_table_entry;
49         uint32_t page_size_index = nds32->mmu_config.default_min_page_size;
50         struct page_table_walker_info_s *page_table_info_p =
51                 &(page_table_info[page_size_index]);
52
53         /* Read L1 Physical Page Table */
54         nds32_get_mapped_reg(nds32, MR1, &value_mr1);
55         load_address = (value_mr1 & page_table_info_p->l1_base_mask) |
56                 ((virtual_address & page_table_info_p->l1_offset_mask) >>
57                  page_table_info_p->l1_offset_shift);
58         /* load_address is physical address */
59         nds32_read_buffer(target, load_address, 4, (uint8_t *)&l1_page_table_entry);
60
61         /* Read L2 Physical Page Table */
62         if (l1_page_table_entry & 0x1) /* L1_PTE not present */
63                 return ERROR_FAIL;
64
65         load_address = (l1_page_table_entry & page_table_info_p->l2_base_mask) |
66                 ((virtual_address & page_table_info_p->l2_offset_mask) >>
67                  page_table_info_p->l2_offset_shift);
68         /* load_address is physical address */
69         nds32_read_buffer(target, load_address, 4, (uint8_t *)&l2_page_table_entry);
70
71         if ((l2_page_table_entry & 0x1) != 0x1) /* L2_PTE not valid */
72                 return ERROR_FAIL;
73
74         *physical_address = (l2_page_table_entry & page_table_info_p->ppn_mask) |
75                 (virtual_address & page_table_info_p->va_offset_mask);
76
77         return ERROR_OK;
78 }