Release 950522
[wine/testsucceed.git] / loader / ldt.c
blob73e1260d73f0410e034b88da21d197e592a86a53
1 /*
2 * LDT manipulation functions
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <strings.h>
11 #include <errno.h>
12 #include "ldt.h"
13 #include "stddebug.h"
14 #include "debug.h"
16 #ifndef WINELIB
18 #ifdef linux
19 #include <linux/unistd.h>
20 #include <linux/head.h>
21 #include <linux/ldt.h>
23 _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
24 #endif /* linux */
26 #if defined(__NetBSD__) || defined(__FreeBSD__)
27 #include <machine/segments.h>
29 extern int i386_get_ldt(int, union descriptor *, int);
30 extern int i386_set_ldt(int, union descriptor *, int);
31 #endif /* __NetBSD__ || __FreeBSD__ */
33 #endif /* ifndef WINELIB */
36 /***********************************************************************
37 * LDT_BytesToEntry
39 * Convert the raw bytes of the descriptor to an ldt_entry structure.
41 static void LDT_BytesToEntry( unsigned long *buffer, ldt_entry *content )
43 content->base = (*buffer >> 16) & 0x0000ffff;
44 content->limit = *buffer & 0x0000ffff;
45 buffer++;
46 content->base |= (*buffer & 0xff000000) | ((*buffer << 16) & 0x00ff0000);
47 content->limit |= (*buffer & 0x000f0000);
48 content->type = (*buffer >> 10) & 3;
49 content->seg_32bit = (*buffer & 0x00400000) != 0;
50 content->read_only = (*buffer & 0x00000200) == 0;
51 content->limit_in_pages = (*buffer & 0x00800000) != 0;
55 /***********************************************************************
56 * LDT_GetEntry
58 * Retrieve an LDT entry.
60 int LDT_GetEntry( int entry, ldt_entry *content )
62 int ret = 0;
64 #ifdef WINELIB
65 content->base = ldt_copy[entry].base;
66 content->limit = ldt_copy[entry].limit;
67 content->type = SEGMENT_DATA;
68 content->seg_32bit = 0;
69 content->read_only = 0;
70 content->limit_in_pages = 0;
71 #else /* WINELIB */
73 #ifdef linux
74 int size = (entry + 1) * 2 * sizeof(long);
75 long *buffer = (long *) malloc( size );
76 ret = modify_ldt( 0, buffer, size );
77 LDT_BytesToEntry( &buffer[entry*2], content );
78 free( buffer );
79 #endif /* linux */
81 #if defined(__NetBSD__) || defined(__FreeBSD__)
82 long buffer[2];
83 ret = i386_get_ldt( entry, (union descriptor *)buffer, 1 );
84 LDT_BytesToEntry( buffer, content );
85 #endif /* __NetBSD__ || __FreeBSD__ */
87 #endif /* WINELIB */
89 return ret;
93 /***********************************************************************
94 * LDT_SetEntry
96 * Set an LDT entry.
98 int LDT_SetEntry( int entry, ldt_entry *content )
100 int ret = 0;
102 dprintf_ldt(stddeb,
103 "LDT_SetEntry: entry=%04x base=%08lx limit=%05lx %s %d-bit flags=%c%c%c\n",
104 entry, content->base, content->limit,
105 content->limit_in_pages ? "pages" : "bytes",
106 content->seg_32bit ? 32 : 16,
107 content->read_only && (content->type & SEGMENT_CODE) ? '-' : 'r',
108 content->read_only || (content->type & SEGMENT_CODE) ? '-' : 'w',
109 (content->type & SEGMENT_CODE) ? 'x' : '-' );
111 #ifndef WINELIB
112 #ifdef linux
114 struct modify_ldt_ldt_s ldt_info;
116 memset( &ldt_info, 0, sizeof(ldt_info) );
117 ldt_info.entry_number = entry;
118 ldt_info.base_addr = content->base;
119 ldt_info.limit = content->limit;
120 ldt_info.seg_32bit = content->seg_32bit != 0;
121 ldt_info.contents = content->type;
122 ldt_info.read_exec_only = content->read_only != 0;
123 ldt_info.limit_in_pages = content->limit_in_pages != 0;
124 ret = modify_ldt(1, &ldt_info, sizeof(ldt_info));
126 #endif /* linux */
128 #if defined(__NetBSD__) || defined(__FreeBSD__)
130 long d[2];
132 d[0] = ((content->base & 0x0000ffff) << 16) |
133 (content->limit & 0x0ffff);
134 d[1] = (content->base & 0xff000000) |
135 ((content->base & 0x00ff0000)>>16) |
136 (content->limit & 0xf0000) |
137 (content->type << 10) |
138 ((content->read_only == 0) << 9) |
139 ((content->seg_32bit != 0) << 22) |
140 ((content->limit_in_pages != 0) << 23) |
141 0xf000;
142 ret = i386_set_ldt(entry, (union descriptor *)d, 1);
143 if (ret < 0)
145 perror("i386_set_ldt");
146 fprintf(stderr,
147 "Did you reconfigure the kernel with \"options USER_LDT\"?\n");
148 exit(1);
151 #endif /* __NetBSD__ || __FreeBSD__ */
152 #endif /* ifndef WINELIB */
154 if (ret < 0) return ret;
155 ldt_copy[entry].base = content->base;
156 if (!content->limit_in_pages) ldt_copy[entry].limit = content->limit;
157 else ldt_copy[entry].limit = (content->limit << 12) | 0x0fff;
158 return ret;
162 /***********************************************************************
163 * LDT_Print
165 * Print the content of the LDT on stdout.
167 void LDT_Print()
169 int i;
171 #ifdef WINELIB
172 for (i = 0; i < LDT_SIZE; i++)
174 if (ldt_copy[i].base || ldt_copy[i].limit)
176 fprintf( stderr, "%04x: sel=%04x base=%08x limit=%05x\n",
177 i, ENTRY_TO_SELECTOR(i),
178 ldt_copy[i].base, ldt_copy[i].limit );
181 #else /* WINELIB */
183 long buffer[2*LDT_SIZE];
184 ldt_entry content;
185 int n;
187 #ifdef linux
188 n = modify_ldt( 0, buffer, sizeof(buffer) ) / 8;
189 #endif /* linux */
190 #if defined(__NetBSD__) || defined(__FreeBSD__)
191 n = i386_get_ldt( 0, (union descriptor *)buffer, LDT_SIZE );
192 #endif /* __NetBSD__ || __FreeBSD__ */
193 for (i = 0; i < n; i++)
195 LDT_BytesToEntry( &buffer[2*i], &content );
196 if (content.base || content.limit)
198 fprintf( stderr, "%04x: sel=%04x base=%08lx limit=%05lx %s type=%d\n",
199 i, ENTRY_TO_SELECTOR(i),
200 content.base, content.limit,
201 content.limit_in_pages ? "(pages)" : "(bytes)",
202 content.type );
205 #endif /* WINELIB */