Sync usage with man page.
[netbsd-mini2440.git] / regress / sys / arch / i386 / ldt / testldt.c
bloba756c118362e865a6b6fd6df85cbe10215e8d1c5
1 /* $NetBSD: testldt.c,v 1.13 2005/12/24 21:43:51 perry Exp $ */
3 /*-
4 * Copyright (c) 1993 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. 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.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <err.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/mman.h>
38 #include <machine/segments.h>
39 #include <machine/sysarch.h>
41 static void
42 set_fs(unsigned int val)
44 __asm volatile("mov %0,%%fs"::"r" ((unsigned short) val));
47 static unsigned char
48 get_fs_byte(const char *addr)
50 unsigned char _v;
52 __asm ("movb %%fs:%1,%0":"=q" (_v):"m" (*addr));
53 return _v;
56 static unsigned short
57 get_cs(void)
59 unsigned short _v;
61 __asm ("movw %%cs,%0": "=r" ((unsigned short) _v));
62 return _v;
65 static int
66 check_desc(int desc)
68 unsigned int sel = LSEL(desc, SEL_UPL);
69 set_fs(sel);
70 return(get_fs_byte((char *) 0));
73 static void
74 gated_call(void)
76 printf("Called from call gate...");
77 __asm volatile("movl %ebp,%esp");
78 __asm volatile("popl %ebp");
79 __asm volatile(".byte 0xcb");
82 static union descriptor *
83 make_sd(void *basep, unsigned limit, int type, int dpl, int seg32, int inpgs)
85 static union descriptor d;
86 unsigned long base = (unsigned long)basep;
88 d.sd.sd_lolimit = limit & 0x0000ffff;
89 d.sd.sd_lobase = base & 0x00ffffff;
90 d.sd.sd_type = type & 0x01f;
91 d.sd.sd_dpl = dpl & 0x3;
92 d.sd.sd_p = 1;
93 d.sd.sd_hilimit = (limit & 0x00ff0000) >> 16;
94 d.sd.sd_xx = 0;
95 d.sd.sd_def32 = seg32?1:0;
96 d.sd.sd_gran = inpgs?1:0;
97 d.sd.sd_hibase = (base & 0xff000000) >> 24;
99 return (&d);
102 static union descriptor *
103 make_gd(void *func, unsigned int sel, unsigned stkcpy, int type, int dpl)
105 static union descriptor d;
106 unsigned long offset = (unsigned long)func;
108 d.gd.gd_looffset = offset & 0x0000ffff;
109 d.gd.gd_selector = sel & 0xffff;
110 d.gd.gd_stkcpy = stkcpy & 0x1ff;
111 d.gd.gd_type = type & 0x1ff;
112 d.gd.gd_dpl = dpl & 0x3;
113 d.gd.gd_p = 1;
114 d.gd.gd_hioffset = (offset & 0xffff0000) >> 16;
116 return(&d);
119 static const char *
120 seg_type_name[] = {
121 "SYSNULL", "SYS286TSS", "SYSLDT", "SYS286BSY",
122 "SYS286CGT", "SYSTASKGT", "SYS286IGT", "SYS286TGT",
123 "SYSNULL2", "SYS386TSS", "SYSNULL3", "SYS386BSY",
124 "SYS386CGT", "SYSNULL4", "SYS386IGT", "SYS386TGT",
125 "MEMRO", "MEMROA", "MEMRW", "MEMRWA",
126 "MEMROD", "MEMRODA", "MEMRWD", "MEMRWDA",
127 "MEME", "MEMEA", "MEMER", "MEMERA",
128 "MEMEC", "MEMEAC", "MEMERC", "MEMERAC"
131 static const char *
132 segtype(unsigned int type)
134 if (type >= 32)
135 return "Out of range";
137 return seg_type_name[type];
141 static void
142 print_ldt(union descriptor *dp)
144 unsigned long base_addr, limit, offset, stack_copy;
145 unsigned int type, dpl;
146 unsigned long lp[2];
148 (void) memcpy(lp, dp, sizeof(lp));
150 base_addr = dp->sd.sd_lobase | (dp->sd.sd_hibase << 24);
151 limit = dp->sd.sd_lolimit | (dp->sd.sd_hilimit << 16);
152 offset = dp->gd.gd_looffset | (dp->gd.gd_hioffset << 16);
154 type = dp->sd.sd_type;
155 dpl = dp->sd.sd_dpl;
156 stack_copy = dp->gd.gd_stkcpy;
158 if (type == SDT_SYS386CGT || type == SDT_SYS286CGT)
159 printf("LDT: Gate Off %8.8lx, Sel %5.5x, Stkcpy %lu DPL %d,"
160 " Type %d/%s\n",
161 offset, dp->gd.gd_selector, stack_copy, dpl,
162 type, segtype(type));
163 else
164 printf("LDT: Seg Base %8.8lx, Limit %5.5lx, DPL %d, "
165 "Type %d/%s\n",
166 base_addr, limit, dpl,
167 type, segtype(type));
168 printf(" ");
169 if (type & 0x1)
170 printf("Accessed, ");
171 if (dp->sd.sd_p)
172 printf("Present, ");
173 if (type != SDT_SYS386CGT && type != SDT_SYS286CGT) {
174 if (type & 0x10)
175 printf("User, ");
176 if (type & 0x08)
177 printf("X, ");
178 if (dp->sd.sd_def32)
179 printf("32-bit, ");
180 else
181 printf("16-bit, ");
182 if (dp->sd.sd_gran)
183 printf("page limit, ");
184 else
185 printf("byte limit, ");
187 printf("\n");
188 printf(" Raw descriptor: %08lx %08lx\n", lp[0], lp[1]);
191 /* ARGSUSED */
192 static void
193 busfault(int signo)
195 errx(1, "%s\n - investigate.", sys_siglist[signo]);
198 static void
199 usage(int status)
201 errx(status, "Usage: testldt [-v]");
204 #define MAX_USER_LDT 1024
207 main(int argc, char *argv[])
209 union descriptor ldt[MAX_USER_LDT];
210 int n, ch;
211 int num;
212 unsigned int cs = get_cs();
213 unsigned char *data;
214 union descriptor *sd, *gd;
215 unsigned char one = 1, two = 2, val;
216 struct sigaction segv_act;
217 int verbose = 0;
219 segv_act.sa_handler = busfault;
220 if (sigaction(SIGBUS, &segv_act, NULL) < 0)
221 err(1, "sigaction");
223 while ((ch = getopt(argc, argv, "v")) != -1) {
224 switch (ch) {
225 case 'v':
226 verbose++;
227 break;
228 default:
229 usage(1);
230 break;
234 printf("Testing i386_get_ldt...\n");
235 if ((num = i386_get_ldt(0, ldt, MAX_USER_LDT)) < 0)
236 err(2, "get_ldt");
238 if (num == 0)
239 errx(1, "i386_get_ldt() returned empty initial LDT");
241 if (verbose) {
242 printf("Got %d (initial) LDT entries\n", num);
243 for (n=0; n < num; n++) {
244 printf("Entry %d: ", n);
245 print_ldt(&ldt[n]);
250 * mmap a data area and assign an LDT to it
252 printf("Testing i386_set_ldt...\n");
253 data = (void *) mmap( (char *)0x005f0000, 0x0fff,
254 PROT_EXEC | PROT_READ | PROT_WRITE,
255 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, (off_t)0);
256 if (data == NULL)
257 err(1, "mmap");
259 if (verbose)
260 printf("data address: %p\n", data);
262 *data = 0x97;
264 /* Get the next free LDT and set it to the allocated data. */
265 sd = make_sd(data, 2048, SDT_MEMRW, SEL_UPL, 0, 0);
266 if ((num = i386_set_ldt(1024, sd, 1)) < 0)
267 err(1, "set_ldt");
269 if (verbose) printf("setldt returned: %d\n", num);
270 if ((n = i386_get_ldt(num, ldt, 1)) < 0)
271 err(1, "get_ldt");
273 if (verbose) {
274 printf("Entry %d: ", num);
275 print_ldt(&ldt[0]);
278 if (verbose)
279 printf("Checking desc (should be 0x97): 0x%x\n",
280 check_desc(num));
281 if (check_desc(num) != 0x97)
282 errx(1, "ERROR: descriptor check failed; "
283 "expected 0x97, got 0x%x", check_desc(num));
286 * Test a Call Gate
288 printf("Making Call Gate\n");
289 fflush(stdout);
291 gd = make_gd((void *)gated_call, cs, 0, SDT_SYS386CGT, SEL_UPL);
292 if ((num = i386_set_ldt(4095, gd, 1)) < 0)
293 err(1, "set_ldt: call gate");
295 if (verbose) {
296 printf("setldt returned: %d\n", num);
297 printf("Call gate sel = 0x%x\n", LSEL(num, SEL_UPL));
300 if ((n = i386_get_ldt(num, ldt, 1)) < 0)
301 err(1, "get_ldt");
303 if (verbose) {
304 printf("Entry %d: ", num);
305 print_ldt(&ldt[0]);
308 printf("Testing call gate...");
309 fflush(stdout);
311 * Long call to call gate.
312 * Only the selector matters; offset is irrelevant.
314 __asm volatile("lcall $0x7fff,$0x0");
316 printf("Gated call returned\n");
319 * Test multiple sets.
322 printf("Testing multiple descriptors at once.\n");
324 sd = (union descriptor *)malloc (sizeof(*sd) * 2);
325 if (sd == NULL)
326 err(1, "can't malloc");
328 sd[0] = *make_sd(&one, 1, SDT_MEMRO, SEL_UPL, 1, 0);
329 sd[1] = *make_sd(&two, 1, SDT_MEMRO, SEL_UPL, 1, 0);
331 if ((num = i386_set_ldt(8000, (union descriptor *)sd, 2)) < 0)
332 err(1, "set_ldt");
334 if (verbose) printf("setldt returned: %d\n", num);
335 if ((n = i386_get_ldt(num, ldt, 2)) < 0)
336 err(1, "get_ldt");
338 if (verbose) {
339 printf("Entry %d: ", num);
340 print_ldt(&ldt[0]);
341 printf("Entry %d: ", num+1);
342 print_ldt(&ldt[1]);
344 val = check_desc(num);
345 printf("contents of segment ONE: %x\n", val);
346 if (val != 1) {
347 errx(1, "ONE has unexpected value %x", val);
349 val = check_desc(num+1);
350 printf("contents of segment TWO: %x\n", val);
351 if (val != 2)
352 errx(1, "TWO has unexpected value %x", val);
354 if ((n = i386_get_ldt(num, ldt, 2)) < 0)
355 err(1, "get_ldt");
357 if (verbose) {
358 printf("Entry %d: ", num);
359 print_ldt(&ldt[0]);
360 printf("Entry %d: ", num+1);
361 print_ldt(&ldt[1]);
364 return 0;