Contiki 3.x
multi-segment.c
1 /*
2  * Copyright (C) 2015, Intel Corporation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "gdt.h"
32 #include "helpers.h"
33 #include "prot-domains.h"
34 #include "segmentation.h"
35 #include "stacks.h"
36 
37 /*---------------------------------------------------------------------------*/
38 static uint32_t
39 segment_desc_compute_base(segment_desc_t desc)
40 {
41  return (desc.base_hi << 24) | (desc.base_mid << 16) | desc.base_lo;
42 }
43 /*---------------------------------------------------------------------------*/
44 void
45 prot_domains_reg_multi_seg(volatile struct dom_kern_data ATTR_KERN_ADDR_SPACE *dkd,
46  uintptr_t mmio, size_t mmio_sz,
47  uintptr_t meta, size_t meta_sz)
48 {
49  segment_desc_t desc;
50  dom_id_t dom_id = PROT_DOMAINS_GET_DOM_ID(dkd);
51  uint32_t kern_data_len;
52  uint32_t tmp;
53 
54  if((dkd < prot_domains_kern_data) ||
55  (prot_domains_kern_data_end <= dkd) ||
56  (((((uintptr_t)dkd) - (uintptr_t)prot_domains_kern_data) %
57  sizeof(dom_kern_data_t)) != 0)) {
58  halt();
59  }
60 
61  KERN_READL(tmp, dkd->ldt[DT_SEL_GET_IDX(LDT_SEL_KERN)].raw_hi);
62  if(tmp != 0) {
63  /* This PDCS was previously initialized, which is disallowed. */
64  halt();
65  }
66 
67  /* Initialize descriptors */
68 
69  if(dom_id == DOM_ID_kern) {
70  kern_data_len = (uint32_t)&_ebss_kern_addr;
71  } else {
72  /* Non-kernel protection domains do not need to access the protection
73  * domain control structures, and they may contain saved register values
74  * that are private to each domain.
75  */
76  kern_data_len = (uint32_t)&_ebss_syscall_addr;
77  }
78  kern_data_len -= (uint32_t)&_sbss_kern_addr;
79 
80  segment_desc_init(&desc, (uint32_t)&_sbss_kern_addr, kern_data_len,
81  /* Every protection domain requires at least read-only access to kernel
82  data to read dom_client_data structures and to support the system call
83  dispatcher, if applicable. Only the kernel protection domain is granted
84  read/write access to the kernel data. */
85  ((dom_id == DOM_ID_kern) ?
86  SEG_TYPE_DATA_RDWR :
87  SEG_TYPE_DATA_RDONLY) |
88  SEG_FLAG(DPL, PRIV_LVL_USER) |
89  SEG_GRAN_BYTE | SEG_DESCTYPE_NSYS);
90 
91  KERN_WRITEL(dkd->ldt[LDT_IDX_KERN].raw_lo, desc.raw_lo);
92  KERN_WRITEL(dkd->ldt[LDT_IDX_KERN].raw_hi, desc.raw_hi);
93 
94  if(mmio_sz != 0) {
95  if(SEG_MAX_BYTE_GRAN_LEN < mmio_sz) {
96  halt();
97  }
98 
99  segment_desc_init(&desc, mmio, mmio_sz,
100  SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
101  SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
102  } else {
103  desc.raw = SEG_DESC_NOT_PRESENT;
104  }
105 
106  KERN_WRITEL(dkd->ldt[LDT_IDX_MMIO].raw_lo, desc.raw_lo);
107  KERN_WRITEL(dkd->ldt[LDT_IDX_MMIO].raw_hi, desc.raw_hi);
108 
109  if(meta_sz != 0) {
110  if(SEG_MAX_BYTE_GRAN_LEN < meta_sz) {
111  halt();
112  }
113 
114  segment_desc_init(&desc, meta, meta_sz,
115  SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
116  SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
117  } else {
118  desc.raw = SEG_DESC_NOT_PRESENT;
119  }
120 
121  KERN_WRITEL(dkd->ldt[LDT_IDX_META].raw_lo, desc.raw_lo);
122  KERN_WRITEL(dkd->ldt[LDT_IDX_META].raw_hi, desc.raw_hi);
123 
124  segment_desc_init(&desc,
125  KERN_DATA_OFF_TO_PHYS_ADDR(dkd->ldt),
126  sizeof(dkd->ldt),
127  SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
128  SEG_DESCTYPE_SYS | SEG_TYPE_LDT);
129  gdt_insert(GDT_IDX_LDT(dom_id), desc);
130 }
131 /*---------------------------------------------------------------------------*/
132 void
133 prot_domains_gdt_init()
134 {
135  int i;
136  segment_desc_t desc;
137 
138  segment_desc_init(&desc,
139  (uint32_t)&_stext_addr,
140  ((uint32_t)&_etext_addr) - (uint32_t)&_stext_addr,
141  SEG_FLAG(DPL, PRIV_LVL_EXC) | SEG_GRAN_BYTE |
142  SEG_DESCTYPE_NSYS |
143 #if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
144  /* The general protection fault handler requires read access to CS */
145  SEG_TYPE_CODE_EXRD
146 #else
147  SEG_TYPE_CODE_EX
148 #endif
149  );
150  gdt_insert_boot(GDT_IDX_CODE_EXC, desc);
151 
152  segment_desc_init(&desc,
153  (uint32_t)&_sdata_addr,
154  ((uint32_t)&_edata_addr) - (uint32_t)&_sdata_addr,
155  SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
156  SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
157  gdt_insert_boot(GDT_IDX_DATA, desc);
158 
159  segment_desc_init(&desc,
160  (uint32_t)&_sbss_kern_addr,
161  ((uint32_t)&_ebss_kern_addr) -
162  (uint32_t)&_sbss_kern_addr,
163  SEG_FLAG(DPL, PRIV_LVL_EXC) | SEG_GRAN_BYTE |
164  SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
165  gdt_insert_boot(GDT_IDX_DATA_KERN_EXC, desc);
166 
167  segment_desc_init(&desc,
168  (uint32_t)DATA_OFF_TO_PHYS_ADDR(stacks_main),
169  STACKS_SIZE_MAIN,
170  SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
171  SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
172  gdt_insert_boot(GDT_IDX_STK, desc);
173 
174  segment_desc_set_limit(&desc, STACKS_SIZE_MAIN + STACKS_SIZE_INT);
175  SEG_SET_FLAG(desc, DPL, PRIV_LVL_INT);
176  gdt_insert_boot(GDT_IDX_STK_INT, desc);
177 
178  segment_desc_set_limit(&desc,
179  STACKS_SIZE_MAIN +
180  STACKS_SIZE_INT +
181  STACKS_SIZE_EXC);
182  SEG_SET_FLAG(desc, DPL, PRIV_LVL_EXC);
183  gdt_insert_boot(GDT_IDX_STK_EXC, desc);
184 
185  /* Not all domains will necessarily be initialized, so this initially marks
186  * all per-domain descriptors not-present.
187  */
188  desc.raw = SEG_DESC_NOT_PRESENT;
189  for(i = 0; i < PROT_DOMAINS_ACTUAL_CNT; i++) {
190 #if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
191  gdt_insert_boot(GDT_IDX_TSS(i), desc);
192 #endif
193  gdt_insert_boot(GDT_IDX_LDT(i), desc);
194  }
195 
196  __asm__ __volatile__ (
197  "mov %[_default_data_], %%ds\n\t"
198  "mov %[_default_data_], %%es\n\t"
199  "mov %[_kern_data_], %%" SEG_KERN "s\n\t"
200  :
201  : [_default_data_] "r"(GDT_SEL_DATA),
202  [_kern_data_] "r"(GDT_SEL_DATA_KERN_EXC));
203 }
204 /*---------------------------------------------------------------------------*/
205 void
206 multi_segment_launch_kernel(void)
207 {
208  /* Update segment registers. */
209  __asm__ __volatile__ (
210  "mov %[_data_seg_], %%ds\n\t"
211  "mov %[_data_seg_], %%es\n\t"
212  "mov %[_kern_seg_], %%" SEG_KERN "s\n\t"
213  "mov %[_data_seg_], %%" SEG_META "s\n\t"
214  :
215  : [_data_seg_] "r" (GDT_SEL_DATA),
216  [_kern_seg_] "r" (LDT_SEL_KERN)
217  );
218 }
219 /*---------------------------------------------------------------------------*/
220 void
221 prot_domains_enable_mmio(void)
222 {
223  __asm__ __volatile__ ("mov %0, %%" SEG_MMIO "s" :: "r" (LDT_SEL_MMIO));
224 }
225 /*---------------------------------------------------------------------------*/
226 void
227 prot_domains_disable_mmio(void)
228 {
229  __asm__ __volatile__ ("mov %0, %%" SEG_KERN "s" :: "r" (LDT_SEL_KERN));
230 }
231 /*---------------------------------------------------------------------------*/
232 uintptr_t
233 prot_domains_lookup_meta_phys_base(dom_client_data_t ATTR_KERN_ADDR_SPACE *drv)
234 {
235  dom_id_t dom_id;
236  segment_desc_t desc;
237  volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE *dkd;
238 
239  KERN_READL(dom_id, drv->dom_id);
240 
241  dkd = prot_domains_kern_data + dom_id;
242 
243  KERN_READL(desc.raw_lo, dkd->ldt[DT_SEL_GET_IDX(LDT_SEL_META)].raw_lo);
244  KERN_READL(desc.raw_hi, dkd->ldt[DT_SEL_GET_IDX(LDT_SEL_META)].raw_hi);
245 
246  return segment_desc_compute_base(desc);
247 }
248 /*---------------------------------------------------------------------------*/
Segment descriptor.
Definition: segmentation.h:89
Data associated with each protection domain that is owned by clients of that domain and used to ident...
Definition: prot-domains.h:247