1/*-
2 * Copyright (c) 2014 Antti Kantee.  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 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <hw/types.h>
27#include <hw/kernel.h>
28
29#include <bmk-core/core.h>
30#include <bmk-core/sched.h>
31
32/*
33 * i386 MD descriptors, assimilated from NetBSD sys/arch/i386/include/segments.h
34 */
35
36struct region_descriptor {
37	unsigned short rd_limit:16;
38	unsigned int rd_base:32;
39} __attribute__((__packed__));
40
41struct gate_descriptor {
42	unsigned gd_looffset:16;
43	unsigned gd_selector:16;
44	unsigned gd_stkcpy:5;
45	unsigned gd_xx:3;
46	unsigned gd_type:5;
47	unsigned gd_dpl:2;
48	unsigned gd_p:1;
49	unsigned gd_hioffset:16;
50} __attribute__((__packed__));
51
52static struct gate_descriptor idt[256];
53
54/* interrupt-not-service-routine */
55void cpu_insr(void);
56
57void
58x86_fillgate(int num, void *fun, int unused)
59{
60	struct gate_descriptor *gd = &idt[num];
61
62	gd->gd_hioffset = (unsigned long)fun >> 16;
63	gd->gd_looffset = (unsigned long)fun;
64
65	/* i was born lucky */
66	gd->gd_selector = 0x8;
67	gd->gd_stkcpy = 0;
68	gd->gd_xx = 0;
69	gd->gd_type = 14;
70	gd->gd_dpl = 0;
71	gd->gd_p = 1;
72}
73
74struct segment_descriptor {
75        unsigned sd_lolimit:16;
76        unsigned sd_lobase:24;
77        unsigned sd_type:5;
78        unsigned sd_dpl:2;
79        unsigned sd_p:1;
80        unsigned sd_hilimit:4;
81        unsigned sd_xx:2;
82        unsigned sd_def32:1;
83        unsigned sd_gran:1;
84        unsigned sd_hibase:8;
85} __attribute__((__packed__));
86
87#define SDT_MEMRWA	19	/* memory read write accessed */
88#define SDT_MEMERA	27	/* memory execute read accessed */
89
90#define SEGMENT_CODE	1
91#define SEGMENT_DATA	2
92#define SEGMENT_GS	3
93
94#define SEG_BYTEGRAN	0
95#define SEG_PAGEGRAN	1
96
97static struct segment_descriptor gdt[4];
98
99static void
100fillsegment(struct segment_descriptor *sd, int type)
101{
102
103	sd->sd_lobase = 0;
104	sd->sd_hibase = 0;
105
106	sd->sd_lolimit = 0xffff;
107	sd->sd_hilimit = 0xf;
108
109	sd->sd_type = type;
110
111	/* i was born luckier */
112	sd->sd_dpl = 0;
113	sd->sd_p = 1;
114	sd->sd_xx = 0;
115	sd->sd_def32 = 1;
116	sd->sd_gran = SEG_PAGEGRAN;
117}
118
119static void
120adjustgs(uintptr_t p)
121{
122	struct segment_descriptor *sd = &gdt[SEGMENT_GS];
123
124	sd->sd_lobase = p & 0xffffff;
125	sd->sd_hibase = (p >> 24) & 0xff;
126
127	__asm__ __volatile__("mov %0, %%gs" :: "r"(8*SEGMENT_GS));
128}
129
130/*
131 * This routine fills out the interrupt descriptors so that
132 * we can handle interrupts without involving a jump to hyperspace.
133 */
134void
135cpu_init(void)
136{
137	struct region_descriptor region;
138
139	fillsegment(&gdt[SEGMENT_CODE], SDT_MEMERA);
140	fillsegment(&gdt[SEGMENT_DATA], SDT_MEMRWA);
141	fillsegment(&gdt[SEGMENT_GS], SDT_MEMRWA);
142
143	region.rd_limit = sizeof(gdt)-1;
144	region.rd_base = (unsigned int)(uintptr_t)(void *)gdt;
145	cpu_lgdt(&region);
146
147	x86_initidt();
148	region.rd_limit = sizeof(idt)-1;
149	region.rd_base = (unsigned int)(uintptr_t)(void *)idt;
150	cpu_lidt(&region);
151
152	x86_initpic();
153
154	x86_initclocks();
155}
156
157void
158bmk_platform_cpu_sched_settls(struct bmk_tcb *next)
159{
160
161	adjustgs(next->btcb_tp);
162}
163