~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to kernel/arch/amd64/src/pm.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2008 Jakub Jermar
 
3
 * Copyright (c) 2005-2006 Ondrej Palkovsky
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 * - Redistributions of source code must retain the above copyright
 
11
 *   notice, this list of conditions and the following disclaimer.
 
12
 * - Redistributions in binary form must reproduce the above copyright
 
13
 *   notice, this list of conditions and the following disclaimer in the
 
14
 *   documentation and/or other materials provided with the distribution.
 
15
 * - The name of the author may not be used to endorse or promote products
 
16
 *   derived from this software without specific prior written permission.
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
28
 */
 
29
 
 
30
/** @addtogroup amd64   
 
31
 * @{
 
32
 */
 
33
/** @file
 
34
 */
 
35
 
 
36
#include <arch.h>
 
37
#include <arch/pm.h>
 
38
#include <arch/asm.h>
 
39
#include <mm/as.h>
 
40
#include <mm/frame.h>
 
41
#include <memstr.h>
 
42
#include <mm/slab.h>
 
43
 
 
44
/*
 
45
 * There is no segmentation in long mode so we set up flat mode. In this
 
46
 * mode, we use, for each privilege level, two segments spanning the
 
47
 * whole memory. One is for code and one is for data.
 
48
 */
 
49
 
 
50
descriptor_t gdt[GDT_ITEMS] = {
 
51
        /* NULL descriptor */
 
52
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 
53
        /* KTEXT descriptor */
 
54
        { .limit_0_15  = 0xffff, 
 
55
          .base_0_15   = 0, 
 
56
          .base_16_23  = 0, 
 
57
          .access      = AR_PRESENT | AR_CODE | DPL_KERNEL | AR_READABLE, 
 
58
          .limit_16_19 = 0xf, 
 
59
          .available   = 0, 
 
60
          .longmode    = 1, 
 
61
          .special     = 0,
 
62
          .granularity = 1, 
 
63
          .base_24_31  = 0 },
 
64
        /* KDATA descriptor */
 
65
        { .limit_0_15  = 0xffff, 
 
66
          .base_0_15   = 0, 
 
67
          .base_16_23  = 0, 
 
68
          .access      = AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_KERNEL, 
 
69
          .limit_16_19 = 0xf, 
 
70
          .available   = 0, 
 
71
          .longmode    = 0, 
 
72
          .special     = 0, 
 
73
          .granularity = 1, 
 
74
          .base_24_31  = 0 },
 
75
        /* UDATA descriptor */
 
76
        { .limit_0_15  = 0xffff, 
 
77
          .base_0_15   = 0, 
 
78
          .base_16_23  = 0, 
 
79
          .access      = AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_USER, 
 
80
          .limit_16_19 = 0xf, 
 
81
          .available   = 0, 
 
82
          .longmode    = 0, 
 
83
          .special     = 1, 
 
84
          .granularity = 1, 
 
85
          .base_24_31  = 0 },
 
86
        /* UTEXT descriptor */
 
87
        { .limit_0_15  = 0xffff, 
 
88
          .base_0_15   = 0, 
 
89
          .base_16_23  = 0, 
 
90
          .access      = AR_PRESENT | AR_CODE | DPL_USER, 
 
91
          .limit_16_19 = 0xf, 
 
92
          .available   = 0, 
 
93
          .longmode    = 1, 
 
94
          .special     = 0, 
 
95
          .granularity = 1, 
 
96
          .base_24_31  = 0 },
 
97
        /* KTEXT 32-bit protected, for protected mode before long mode */
 
98
        { .limit_0_15  = 0xffff, 
 
99
          .base_0_15   = 0, 
 
100
          .base_16_23  = 0, 
 
101
          .access      = AR_PRESENT | AR_CODE | DPL_KERNEL | AR_READABLE, 
 
102
          .limit_16_19 = 0xf, 
 
103
          .available   = 0, 
 
104
          .longmode    = 0, 
 
105
          .special     = 1,
 
106
          .granularity = 1, 
 
107
          .base_24_31  = 0 },
 
108
        /* TSS descriptor - set up will be completed later,
 
109
         * on AMD64 it is 64-bit - 2 items in table */
 
110
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 
111
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 
112
        /* VESA Init descriptor */
 
113
#ifdef CONFIG_FB        
 
114
        { 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_CODE | DPL_KERNEL,
 
115
          0xf, 0, 0, 0, 0, 0
 
116
        }
 
117
#endif
 
118
};
 
119
 
 
120
idescriptor_t idt[IDT_ITEMS];
 
121
 
 
122
ptr_16_64_t gdtr = {.limit = sizeof(gdt), .base = (uint64_t) gdt };
 
123
ptr_16_64_t idtr = {.limit = sizeof(idt), .base = (uint64_t) idt };
 
124
 
 
125
static tss_t tss;
 
126
tss_t *tss_p = NULL;
 
127
 
 
128
void gdt_tss_setbase(descriptor_t *d, uintptr_t base)
 
129
{
 
130
        tss_descriptor_t *td = (tss_descriptor_t *) d;
 
131
 
 
132
        td->base_0_15 = base & 0xffff;
 
133
        td->base_16_23 = ((base) >> 16) & 0xff;
 
134
        td->base_24_31 = ((base) >> 24) & 0xff;
 
135
        td->base_32_63 = ((base) >> 32);
 
136
}
 
137
 
 
138
void gdt_tss_setlimit(descriptor_t *d, uint32_t limit)
 
139
{
 
140
        tss_descriptor_t *td = (tss_descriptor_t *) d;
 
141
        
 
142
        td->limit_0_15 = limit & 0xffff;
 
143
        td->limit_16_19 = (limit >> 16) & 0xf;
 
144
}
 
145
 
 
146
void idt_setoffset(idescriptor_t *d, uintptr_t offset)
 
147
{
 
148
        /*
 
149
         * Offset is a linear address.
 
150
         */
 
151
        d->offset_0_15 = offset & 0xffff;
 
152
        d->offset_16_31 = offset >> 16 & 0xffff;
 
153
        d->offset_32_63 = offset >> 32;
 
154
}
 
155
 
 
156
void tss_initialize(tss_t *t)
 
157
{
 
158
        memsetb(t, sizeof(tss_t), 0);
 
159
}
 
160
 
 
161
/*
 
162
 * This function takes care of proper setup of IDT and IDTR.
 
163
 */
 
164
void idt_init(void)
 
165
{
 
166
        idescriptor_t *d;
 
167
        int i;
 
168
 
 
169
        for (i = 0; i < IDT_ITEMS; i++) {
 
170
                d = &idt[i];
 
171
 
 
172
                d->unused = 0;
 
173
                d->selector = gdtselector(KTEXT_DES);
 
174
 
 
175
                d->present = 1;
 
176
                d->type = AR_INTERRUPT; /* masking interrupt */
 
177
 
 
178
                idt_setoffset(d, ((uintptr_t) interrupt_handlers) +
 
179
                    i * interrupt_handler_size);
 
180
        }
 
181
}
 
182
 
 
183
/** Initialize segmentation - code/data/idt tables
 
184
 *
 
185
 */
 
186
void pm_init(void)
 
187
{
 
188
        descriptor_t *gdt_p = (descriptor_t *) gdtr.base;
 
189
        tss_descriptor_t *tss_desc;
 
190
        
 
191
        /*
 
192
         * Each CPU has its private GDT and TSS.
 
193
         * All CPUs share one IDT.
 
194
         */
 
195
        
 
196
        if (config.cpu_active == 1) {
 
197
                idt_init();
 
198
                /*
 
199
                 * NOTE: bootstrap CPU has statically allocated TSS, because
 
200
                 * the heap hasn't been initialized so far.
 
201
                 */
 
202
                tss_p = &tss;
 
203
        } else {
 
204
                /* We are going to use malloc, which may return
 
205
                 * non boot-mapped pointer, initialize the CR3 register
 
206
                 * ahead of page_init */
 
207
                write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
 
208
                
 
209
                tss_p = (tss_t *) malloc(sizeof(tss_t), FRAME_ATOMIC);
 
210
                if (!tss_p)
 
211
                        panic("Cannot allocate TSS.");
 
212
        }
 
213
        
 
214
        tss_initialize(tss_p);
 
215
        
 
216
        tss_desc = (tss_descriptor_t *) (&gdt_p[TSS_DES]);
 
217
        tss_desc->present = 1;
 
218
        tss_desc->type = AR_TSS;
 
219
        tss_desc->dpl = PL_KERNEL;
 
220
        
 
221
        gdt_tss_setbase(&gdt_p[TSS_DES], (uintptr_t) tss_p);
 
222
        gdt_tss_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE - 1);
 
223
        
 
224
        gdtr_load(&gdtr);
 
225
        idtr_load(&idtr);
 
226
        /*
 
227
         * As of this moment, the current CPU has its own GDT pointing
 
228
         * to its own TSS. We just need to load the TR register.
 
229
         */
 
230
        tr_load(gdtselector(TSS_DES));
 
231
}
 
232
 
 
233
/** @}
 
234
 */