1 /*
2  * Copyright (c) 2009 Corey Tabaka
3  * Copyright (c) 2018 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files
7  * (the "Software"), to deal in the Software without restriction,
8  * including without limitation the rights to use, copy, modify, merge,
9  * publish, distribute, sublicense, and/or sell copies of the Software,
10  * and to permit persons to whom the Software is furnished to do so,
11  * subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <arch/arch_ops.h>
26 #include <arch/x86/descriptor.h>
27 #include <compiler.h>
28 #include <debug.h>
29 
30 /*
31  * Descriptors are always 64-bit except TSS (or LDT) Descriptor in 64-bit mode.
32  * In 64-bit mode, TSS descriptor is defined as 128 bits, low 64 bits of TSS
33  * have same definition as legacy descriptor, high 64 bits contain base address
34  * bits 63:32 of descriptor.
35  *
36  * High 32 bits of base address of descriptor should be set when dealing with
37  * TSS descriptor.
38  */
39 typedef union {
40     struct {
41         uint16_t limit_15_0;
42         uint16_t base_15_0;
43         uint8_t base_23_16;
44 
45         uint8_t type : 4;
46         uint8_t s : 1;
47         uint8_t dpl : 2;
48         uint8_t p : 1;
49 
50         uint8_t limit_19_16 : 4;
51         uint8_t avl : 1;
52         uint8_t reserved_0 : 1;
53         uint8_t d_b : 1;
54         uint8_t g : 1;
55 
56         uint8_t base_31_24;
57     } __PACKED legacy;
58 
59     struct {
60         uint32_t base_32_63;
61         uint16_t rsvd_1;
62         uint16_t rsvd_2;
63     } __PACKED tss_high;
64 } __PACKED seg_desc_t;
65 
66 extern seg_desc_t _gdt[];
67 
set_global_desc(seg_sel_t sel,void * base,uint32_t limit,uint8_t present,uint8_t ring,uint8_t sys,uint8_t type,uint8_t gran,uint8_t bits)68 void set_global_desc(seg_sel_t sel,
69         void *base,
70         uint32_t limit,
71         uint8_t present,
72         uint8_t ring,
73         uint8_t sys,
74         uint8_t type,
75         uint8_t gran,
76         uint8_t bits)
77 {
78     /* convert selector into index */
79     uint16_t index = sel >> 3;
80 
81     /* For legacy descriptors and low 32 bit of 64-bit TSS only */
82     _gdt[index].legacy.limit_15_0  = limit & 0x0000ffff;
83     _gdt[index].legacy.limit_19_16 = (limit & 0x000f0000) >> 16;
84 
85     _gdt[index].legacy.base_15_0  = ((uint64_t)base) & 0x0000ffff;
86     _gdt[index].legacy.base_23_16 = (((uint64_t)base) & 0x00ff0000) >> 16;
87     _gdt[index].legacy.base_31_24 = ((uint64_t)base) >> 24;
88 
89     _gdt[index].legacy.type = type & 0x0f;    /* segment type */
90     _gdt[index].legacy.p    = (present != 0); /* present */
91     _gdt[index].legacy.dpl  = ring & 0x03;    /* descriptor privilege level */
92     _gdt[index].legacy.g    = (gran != 0);    /* granularity */
93     _gdt[index].legacy.s    = (sys != 0);     /* system / non-system */
94     _gdt[index].legacy.d_b  = (bits != 0);    /* 16 / 32 bit */
95 
96     /* high bits of 64-bit TSS only */
97     if (sel >= TSS_SELECTOR) {
98         index = sel >> 3;
99 
100         /* update high bits of 64-bit TSS now */
101         _gdt[index + 1].tss_high.base_32_63 = (uint64_t)base >> 32;
102     }
103 }
104 
get_tss_base(void)105 tss_t *get_tss_base(void)
106 {
107     volatile uint cpu = arch_curr_cpu_num();
108 
109     if (cpu >= SMP_MAX_CPUS) {
110         panic("Invalid CPU ID\n");
111     }
112 
113     return &system_tss[cpu];
114 }
115