Commit 3feb88562d149f078319e5a1b2f7acaa10251a5c
Committed by
Linus Torvalds
1 parent
54d8d3b5a0
Exists in
master
and in
7 other branches
[PATCH] uml: check for differences in host support
If running on a host not supporting TLS (for instance 2.4) we should report that cleanly to the user, instead of printing not comprehensible "error 5" for that. Additionally, i386 and x86_64 support different ranges for user_desc->entry_number, and we must account for that; we couldn't pass ourselves -1 because we need to override previously existing TLS descriptors which glibc has possibly set, so test at startup the range to use. x86 and x86_64 existing ranges are hardcoded. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Acked-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 8 changed files with 102 additions and 6 deletions Inline Diff
arch/um/include/os.h
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #ifndef __OS_H__ | 6 | #ifndef __OS_H__ |
7 | #define __OS_H__ | 7 | #define __OS_H__ |
8 | 8 | ||
9 | #include "uml-config.h" | 9 | #include "uml-config.h" |
10 | #include "asm/types.h" | 10 | #include "asm/types.h" |
11 | #include "../os/include/file.h" | 11 | #include "../os/include/file.h" |
12 | #include "sysdep/ptrace.h" | 12 | #include "sysdep/ptrace.h" |
13 | #include "kern_util.h" | 13 | #include "kern_util.h" |
14 | #include "skas/mm_id.h" | 14 | #include "skas/mm_id.h" |
15 | #include "irq_user.h" | 15 | #include "irq_user.h" |
16 | #include "sysdep/tls.h" | 16 | #include "sysdep/tls.h" |
17 | 17 | ||
18 | #define OS_TYPE_FILE 1 | 18 | #define OS_TYPE_FILE 1 |
19 | #define OS_TYPE_DIR 2 | 19 | #define OS_TYPE_DIR 2 |
20 | #define OS_TYPE_SYMLINK 3 | 20 | #define OS_TYPE_SYMLINK 3 |
21 | #define OS_TYPE_CHARDEV 4 | 21 | #define OS_TYPE_CHARDEV 4 |
22 | #define OS_TYPE_BLOCKDEV 5 | 22 | #define OS_TYPE_BLOCKDEV 5 |
23 | #define OS_TYPE_FIFO 6 | 23 | #define OS_TYPE_FIFO 6 |
24 | #define OS_TYPE_SOCK 7 | 24 | #define OS_TYPE_SOCK 7 |
25 | 25 | ||
26 | /* os_access() flags */ | 26 | /* os_access() flags */ |
27 | #define OS_ACC_F_OK 0 /* Test for existence. */ | 27 | #define OS_ACC_F_OK 0 /* Test for existence. */ |
28 | #define OS_ACC_X_OK 1 /* Test for execute permission. */ | 28 | #define OS_ACC_X_OK 1 /* Test for execute permission. */ |
29 | #define OS_ACC_W_OK 2 /* Test for write permission. */ | 29 | #define OS_ACC_W_OK 2 /* Test for write permission. */ |
30 | #define OS_ACC_R_OK 4 /* Test for read permission. */ | 30 | #define OS_ACC_R_OK 4 /* Test for read permission. */ |
31 | #define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ | 31 | #define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * types taken from stat_file() in hostfs_user.c | 34 | * types taken from stat_file() in hostfs_user.c |
35 | * (if they are wrong here, they are wrong there...). | 35 | * (if they are wrong here, they are wrong there...). |
36 | */ | 36 | */ |
37 | struct uml_stat { | 37 | struct uml_stat { |
38 | int ust_dev; /* device */ | 38 | int ust_dev; /* device */ |
39 | unsigned long long ust_ino; /* inode */ | 39 | unsigned long long ust_ino; /* inode */ |
40 | int ust_mode; /* protection */ | 40 | int ust_mode; /* protection */ |
41 | int ust_nlink; /* number of hard links */ | 41 | int ust_nlink; /* number of hard links */ |
42 | int ust_uid; /* user ID of owner */ | 42 | int ust_uid; /* user ID of owner */ |
43 | int ust_gid; /* group ID of owner */ | 43 | int ust_gid; /* group ID of owner */ |
44 | unsigned long long ust_size; /* total size, in bytes */ | 44 | unsigned long long ust_size; /* total size, in bytes */ |
45 | int ust_blksize; /* blocksize for filesystem I/O */ | 45 | int ust_blksize; /* blocksize for filesystem I/O */ |
46 | unsigned long long ust_blocks; /* number of blocks allocated */ | 46 | unsigned long long ust_blocks; /* number of blocks allocated */ |
47 | unsigned long ust_atime; /* time of last access */ | 47 | unsigned long ust_atime; /* time of last access */ |
48 | unsigned long ust_mtime; /* time of last modification */ | 48 | unsigned long ust_mtime; /* time of last modification */ |
49 | unsigned long ust_ctime; /* time of last change */ | 49 | unsigned long ust_ctime; /* time of last change */ |
50 | }; | 50 | }; |
51 | 51 | ||
52 | struct openflags { | 52 | struct openflags { |
53 | unsigned int r : 1; | 53 | unsigned int r : 1; |
54 | unsigned int w : 1; | 54 | unsigned int w : 1; |
55 | unsigned int s : 1; /* O_SYNC */ | 55 | unsigned int s : 1; /* O_SYNC */ |
56 | unsigned int c : 1; /* O_CREAT */ | 56 | unsigned int c : 1; /* O_CREAT */ |
57 | unsigned int t : 1; /* O_TRUNC */ | 57 | unsigned int t : 1; /* O_TRUNC */ |
58 | unsigned int a : 1; /* O_APPEND */ | 58 | unsigned int a : 1; /* O_APPEND */ |
59 | unsigned int e : 1; /* O_EXCL */ | 59 | unsigned int e : 1; /* O_EXCL */ |
60 | unsigned int cl : 1; /* FD_CLOEXEC */ | 60 | unsigned int cl : 1; /* FD_CLOEXEC */ |
61 | }; | 61 | }; |
62 | 62 | ||
63 | #define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ | 63 | #define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ |
64 | .t = 0, .a = 0, .e = 0, .cl = 0 }) | 64 | .t = 0, .a = 0, .e = 0, .cl = 0 }) |
65 | 65 | ||
66 | static inline struct openflags of_read(struct openflags flags) | 66 | static inline struct openflags of_read(struct openflags flags) |
67 | { | 67 | { |
68 | flags.r = 1; | 68 | flags.r = 1; |
69 | return(flags); | 69 | return(flags); |
70 | } | 70 | } |
71 | 71 | ||
72 | static inline struct openflags of_write(struct openflags flags) | 72 | static inline struct openflags of_write(struct openflags flags) |
73 | { | 73 | { |
74 | flags.w = 1; | 74 | flags.w = 1; |
75 | return(flags); | 75 | return(flags); |
76 | } | 76 | } |
77 | 77 | ||
78 | static inline struct openflags of_rdwr(struct openflags flags) | 78 | static inline struct openflags of_rdwr(struct openflags flags) |
79 | { | 79 | { |
80 | return(of_read(of_write(flags))); | 80 | return(of_read(of_write(flags))); |
81 | } | 81 | } |
82 | 82 | ||
83 | static inline struct openflags of_set_rw(struct openflags flags, int r, int w) | 83 | static inline struct openflags of_set_rw(struct openflags flags, int r, int w) |
84 | { | 84 | { |
85 | flags.r = r; | 85 | flags.r = r; |
86 | flags.w = w; | 86 | flags.w = w; |
87 | return(flags); | 87 | return(flags); |
88 | } | 88 | } |
89 | 89 | ||
90 | static inline struct openflags of_sync(struct openflags flags) | 90 | static inline struct openflags of_sync(struct openflags flags) |
91 | { | 91 | { |
92 | flags.s = 1; | 92 | flags.s = 1; |
93 | return(flags); | 93 | return(flags); |
94 | } | 94 | } |
95 | 95 | ||
96 | static inline struct openflags of_create(struct openflags flags) | 96 | static inline struct openflags of_create(struct openflags flags) |
97 | { | 97 | { |
98 | flags.c = 1; | 98 | flags.c = 1; |
99 | return(flags); | 99 | return(flags); |
100 | } | 100 | } |
101 | 101 | ||
102 | static inline struct openflags of_trunc(struct openflags flags) | 102 | static inline struct openflags of_trunc(struct openflags flags) |
103 | { | 103 | { |
104 | flags.t = 1; | 104 | flags.t = 1; |
105 | return(flags); | 105 | return(flags); |
106 | } | 106 | } |
107 | 107 | ||
108 | static inline struct openflags of_append(struct openflags flags) | 108 | static inline struct openflags of_append(struct openflags flags) |
109 | { | 109 | { |
110 | flags.a = 1; | 110 | flags.a = 1; |
111 | return(flags); | 111 | return(flags); |
112 | } | 112 | } |
113 | 113 | ||
114 | static inline struct openflags of_excl(struct openflags flags) | 114 | static inline struct openflags of_excl(struct openflags flags) |
115 | { | 115 | { |
116 | flags.e = 1; | 116 | flags.e = 1; |
117 | return(flags); | 117 | return(flags); |
118 | } | 118 | } |
119 | 119 | ||
120 | static inline struct openflags of_cloexec(struct openflags flags) | 120 | static inline struct openflags of_cloexec(struct openflags flags) |
121 | { | 121 | { |
122 | flags.cl = 1; | 122 | flags.cl = 1; |
123 | return(flags); | 123 | return(flags); |
124 | } | 124 | } |
125 | 125 | ||
126 | /* file.c */ | 126 | /* file.c */ |
127 | extern int os_stat_file(const char *file_name, struct uml_stat *buf); | 127 | extern int os_stat_file(const char *file_name, struct uml_stat *buf); |
128 | extern int os_stat_fd(const int fd, struct uml_stat *buf); | 128 | extern int os_stat_fd(const int fd, struct uml_stat *buf); |
129 | extern int os_access(const char *file, int mode); | 129 | extern int os_access(const char *file, int mode); |
130 | extern void os_print_error(int error, const char* str); | 130 | extern void os_print_error(int error, const char* str); |
131 | extern int os_get_exec_close(int fd, int *close_on_exec); | 131 | extern int os_get_exec_close(int fd, int *close_on_exec); |
132 | extern int os_set_exec_close(int fd, int close_on_exec); | 132 | extern int os_set_exec_close(int fd, int close_on_exec); |
133 | extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); | 133 | extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); |
134 | extern int os_window_size(int fd, int *rows, int *cols); | 134 | extern int os_window_size(int fd, int *rows, int *cols); |
135 | extern int os_new_tty_pgrp(int fd, int pid); | 135 | extern int os_new_tty_pgrp(int fd, int pid); |
136 | extern int os_get_ifname(int fd, char *namebuf); | 136 | extern int os_get_ifname(int fd, char *namebuf); |
137 | extern int os_set_slip(int fd); | 137 | extern int os_set_slip(int fd); |
138 | extern int os_set_owner(int fd, int pid); | 138 | extern int os_set_owner(int fd, int pid); |
139 | extern int os_sigio_async(int master, int slave); | 139 | extern int os_sigio_async(int master, int slave); |
140 | extern int os_mode_fd(int fd, int mode); | 140 | extern int os_mode_fd(int fd, int mode); |
141 | 141 | ||
142 | extern int os_seek_file(int fd, __u64 offset); | 142 | extern int os_seek_file(int fd, __u64 offset); |
143 | extern int os_open_file(char *file, struct openflags flags, int mode); | 143 | extern int os_open_file(char *file, struct openflags flags, int mode); |
144 | extern int os_read_file(int fd, void *buf, int len); | 144 | extern int os_read_file(int fd, void *buf, int len); |
145 | extern int os_write_file(int fd, const void *buf, int count); | 145 | extern int os_write_file(int fd, const void *buf, int count); |
146 | extern int os_file_size(char *file, unsigned long long *size_out); | 146 | extern int os_file_size(char *file, unsigned long long *size_out); |
147 | extern int os_file_modtime(char *file, unsigned long *modtime); | 147 | extern int os_file_modtime(char *file, unsigned long *modtime); |
148 | extern int os_pipe(int *fd, int stream, int close_on_exec); | 148 | extern int os_pipe(int *fd, int stream, int close_on_exec); |
149 | extern int os_set_fd_async(int fd, int owner); | 149 | extern int os_set_fd_async(int fd, int owner); |
150 | extern int os_clear_fd_async(int fd); | 150 | extern int os_clear_fd_async(int fd); |
151 | extern int os_set_fd_block(int fd, int blocking); | 151 | extern int os_set_fd_block(int fd, int blocking); |
152 | extern int os_accept_connection(int fd); | 152 | extern int os_accept_connection(int fd); |
153 | extern int os_create_unix_socket(char *file, int len, int close_on_exec); | 153 | extern int os_create_unix_socket(char *file, int len, int close_on_exec); |
154 | extern int os_shutdown_socket(int fd, int r, int w); | 154 | extern int os_shutdown_socket(int fd, int r, int w); |
155 | extern void os_close_file(int fd); | 155 | extern void os_close_file(int fd); |
156 | extern int os_rcv_fd(int fd, int *helper_pid_out); | 156 | extern int os_rcv_fd(int fd, int *helper_pid_out); |
157 | extern int create_unix_socket(char *file, int len, int close_on_exec); | 157 | extern int create_unix_socket(char *file, int len, int close_on_exec); |
158 | extern int os_connect_socket(char *name); | 158 | extern int os_connect_socket(char *name); |
159 | extern int os_file_type(char *file); | 159 | extern int os_file_type(char *file); |
160 | extern int os_file_mode(char *file, struct openflags *mode_out); | 160 | extern int os_file_mode(char *file, struct openflags *mode_out); |
161 | extern int os_lock_file(int fd, int excl); | 161 | extern int os_lock_file(int fd, int excl); |
162 | extern void os_flush_stdout(void); | 162 | extern void os_flush_stdout(void); |
163 | extern int os_stat_filesystem(char *path, long *bsize_out, | 163 | extern int os_stat_filesystem(char *path, long *bsize_out, |
164 | long long *blocks_out, long long *bfree_out, | 164 | long long *blocks_out, long long *bfree_out, |
165 | long long *bavail_out, long long *files_out, | 165 | long long *bavail_out, long long *files_out, |
166 | long long *ffree_out, void *fsid_out, | 166 | long long *ffree_out, void *fsid_out, |
167 | int fsid_size, long *namelen_out, | 167 | int fsid_size, long *namelen_out, |
168 | long *spare_out); | 168 | long *spare_out); |
169 | extern int os_change_dir(char *dir); | 169 | extern int os_change_dir(char *dir); |
170 | extern int os_fchange_dir(int fd); | 170 | extern int os_fchange_dir(int fd); |
171 | 171 | ||
172 | /* start_up.c */ | 172 | /* start_up.c */ |
173 | extern void os_early_checks(void); | 173 | extern void os_early_checks(void); |
174 | extern int can_do_skas(void); | 174 | extern int can_do_skas(void); |
175 | extern void os_check_bugs(void); | 175 | extern void os_check_bugs(void); |
176 | extern void check_host_supports_tls(int *supports_tls, int *tls_min); | ||
176 | 177 | ||
177 | /* Make sure they are clear when running in TT mode. Required by | 178 | /* Make sure they are clear when running in TT mode. Required by |
178 | * SEGV_MAYBE_FIXABLE */ | 179 | * SEGV_MAYBE_FIXABLE */ |
179 | #ifdef UML_CONFIG_MODE_SKAS | 180 | #ifdef UML_CONFIG_MODE_SKAS |
180 | #define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0) | 181 | #define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0) |
181 | #else | 182 | #else |
182 | #define clear_can_do_skas() do {} while (0) | 183 | #define clear_can_do_skas() do {} while (0) |
183 | #endif | 184 | #endif |
184 | 185 | ||
185 | /* mem.c */ | 186 | /* mem.c */ |
186 | extern int create_mem_file(unsigned long long len); | 187 | extern int create_mem_file(unsigned long long len); |
187 | 188 | ||
188 | /* process.c */ | 189 | /* process.c */ |
189 | extern unsigned long os_process_pc(int pid); | 190 | extern unsigned long os_process_pc(int pid); |
190 | extern int os_process_parent(int pid); | 191 | extern int os_process_parent(int pid); |
191 | extern void os_stop_process(int pid); | 192 | extern void os_stop_process(int pid); |
192 | extern void os_kill_process(int pid, int reap_child); | 193 | extern void os_kill_process(int pid, int reap_child); |
193 | extern void os_kill_ptraced_process(int pid, int reap_child); | 194 | extern void os_kill_ptraced_process(int pid, int reap_child); |
194 | extern void os_usr1_process(int pid); | 195 | extern void os_usr1_process(int pid); |
195 | extern long os_ptrace_ldt(long pid, long addr, long data); | 196 | extern long os_ptrace_ldt(long pid, long addr, long data); |
196 | 197 | ||
197 | extern int os_getpid(void); | 198 | extern int os_getpid(void); |
198 | extern int os_getpgrp(void); | 199 | extern int os_getpgrp(void); |
199 | 200 | ||
200 | extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); | 201 | extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); |
201 | extern void init_new_thread_signals(int altstack); | 202 | extern void init_new_thread_signals(int altstack); |
202 | extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); | 203 | extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); |
203 | 204 | ||
204 | extern int os_map_memory(void *virt, int fd, unsigned long long off, | 205 | extern int os_map_memory(void *virt, int fd, unsigned long long off, |
205 | unsigned long len, int r, int w, int x); | 206 | unsigned long len, int r, int w, int x); |
206 | extern int os_protect_memory(void *addr, unsigned long len, | 207 | extern int os_protect_memory(void *addr, unsigned long len, |
207 | int r, int w, int x); | 208 | int r, int w, int x); |
208 | extern int os_unmap_memory(void *addr, int len); | 209 | extern int os_unmap_memory(void *addr, int len); |
209 | extern int os_drop_memory(void *addr, int length); | 210 | extern int os_drop_memory(void *addr, int length); |
210 | extern int can_drop_memory(void); | 211 | extern int can_drop_memory(void); |
211 | extern void os_flush_stdout(void); | 212 | extern void os_flush_stdout(void); |
212 | 213 | ||
213 | /* tt.c | 214 | /* tt.c |
214 | * for tt mode only (will be deleted in future...) | 215 | * for tt mode only (will be deleted in future...) |
215 | */ | 216 | */ |
216 | extern void forward_ipi(int fd, int pid); | 217 | extern void forward_ipi(int fd, int pid); |
217 | extern void kill_child_dead(int pid); | 218 | extern void kill_child_dead(int pid); |
218 | extern void stop(void); | 219 | extern void stop(void); |
219 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); | 220 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); |
220 | extern int protect_memory(unsigned long addr, unsigned long len, | 221 | extern int protect_memory(unsigned long addr, unsigned long len, |
221 | int r, int w, int x, int must_succeed); | 222 | int r, int w, int x, int must_succeed); |
222 | extern void forward_pending_sigio(int target); | 223 | extern void forward_pending_sigio(int target); |
223 | extern int start_fork_tramp(void *arg, unsigned long temp_stack, | 224 | extern int start_fork_tramp(void *arg, unsigned long temp_stack, |
224 | int clone_flags, int (*tramp)(void *)); | 225 | int clone_flags, int (*tramp)(void *)); |
225 | 226 | ||
226 | /* uaccess.c */ | 227 | /* uaccess.c */ |
227 | extern unsigned long __do_user_copy(void *to, const void *from, int n, | 228 | extern unsigned long __do_user_copy(void *to, const void *from, int n, |
228 | void **fault_addr, void **fault_catcher, | 229 | void **fault_addr, void **fault_catcher, |
229 | void (*op)(void *to, const void *from, | 230 | void (*op)(void *to, const void *from, |
230 | int n), int *faulted_out); | 231 | int n), int *faulted_out); |
231 | 232 | ||
232 | /* helper.c */ | 233 | /* helper.c */ |
233 | extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, | 234 | extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, |
234 | unsigned long *stack_out); | 235 | unsigned long *stack_out); |
235 | extern int run_helper_thread(int (*proc)(void *), void *arg, | 236 | extern int run_helper_thread(int (*proc)(void *), void *arg, |
236 | unsigned int flags, unsigned long *stack_out, | 237 | unsigned int flags, unsigned long *stack_out, |
237 | int stack_order); | 238 | int stack_order); |
238 | extern int helper_wait(int pid); | 239 | extern int helper_wait(int pid); |
239 | 240 | ||
240 | 241 | ||
241 | /* tls.c */ | 242 | /* tls.c */ |
242 | extern int os_set_thread_area(user_desc_t *info, int pid); | 243 | extern int os_set_thread_area(user_desc_t *info, int pid); |
243 | extern int os_get_thread_area(user_desc_t *info, int pid); | 244 | extern int os_get_thread_area(user_desc_t *info, int pid); |
244 | 245 | ||
245 | /* umid.c */ | 246 | /* umid.c */ |
246 | extern int umid_file_name(char *name, char *buf, int len); | 247 | extern int umid_file_name(char *name, char *buf, int len); |
247 | extern int set_umid(char *name); | 248 | extern int set_umid(char *name); |
248 | extern char *get_umid(void); | 249 | extern char *get_umid(void); |
249 | 250 | ||
250 | /* signal.c */ | 251 | /* signal.c */ |
251 | extern void set_sigstack(void *sig_stack, int size); | 252 | extern void set_sigstack(void *sig_stack, int size); |
252 | extern void remove_sigstack(void); | 253 | extern void remove_sigstack(void); |
253 | extern void set_handler(int sig, void (*handler)(int), int flags, ...); | 254 | extern void set_handler(int sig, void (*handler)(int), int flags, ...); |
254 | extern int change_sig(int signal, int on); | 255 | extern int change_sig(int signal, int on); |
255 | extern void block_signals(void); | 256 | extern void block_signals(void); |
256 | extern void unblock_signals(void); | 257 | extern void unblock_signals(void); |
257 | extern int get_signals(void); | 258 | extern int get_signals(void); |
258 | extern int set_signals(int enable); | 259 | extern int set_signals(int enable); |
259 | extern void os_usr1_signal(int on); | 260 | extern void os_usr1_signal(int on); |
260 | 261 | ||
261 | /* trap.c */ | 262 | /* trap.c */ |
262 | extern void os_fill_handlinfo(struct kern_handlers h); | 263 | extern void os_fill_handlinfo(struct kern_handlers h); |
263 | extern void do_longjmp(void *p, int val); | 264 | extern void do_longjmp(void *p, int val); |
264 | 265 | ||
265 | /* util.c */ | 266 | /* util.c */ |
266 | extern void stack_protections(unsigned long address); | 267 | extern void stack_protections(unsigned long address); |
267 | extern void task_protections(unsigned long address); | 268 | extern void task_protections(unsigned long address); |
268 | extern int raw(int fd); | 269 | extern int raw(int fd); |
269 | extern void setup_machinename(char *machine_out); | 270 | extern void setup_machinename(char *machine_out); |
270 | extern void setup_hostinfo(void); | 271 | extern void setup_hostinfo(void); |
271 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); | 272 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); |
272 | 273 | ||
273 | /* time.c */ | 274 | /* time.c */ |
274 | #define BILLION (1000 * 1000 * 1000) | 275 | #define BILLION (1000 * 1000 * 1000) |
275 | 276 | ||
276 | extern void switch_timers(int to_real); | 277 | extern void switch_timers(int to_real); |
277 | extern void idle_sleep(int secs); | 278 | extern void idle_sleep(int secs); |
278 | extern void enable_timer(void); | 279 | extern void enable_timer(void); |
279 | extern void disable_timer(void); | 280 | extern void disable_timer(void); |
280 | extern void user_time_init(void); | 281 | extern void user_time_init(void); |
281 | extern void uml_idle_timer(void); | 282 | extern void uml_idle_timer(void); |
282 | extern unsigned long long os_nsecs(void); | 283 | extern unsigned long long os_nsecs(void); |
283 | 284 | ||
284 | /* skas/mem.c */ | 285 | /* skas/mem.c */ |
285 | extern long run_syscall_stub(struct mm_id * mm_idp, | 286 | extern long run_syscall_stub(struct mm_id * mm_idp, |
286 | int syscall, unsigned long *args, long expected, | 287 | int syscall, unsigned long *args, long expected, |
287 | void **addr, int done); | 288 | void **addr, int done); |
288 | extern long syscall_stub_data(struct mm_id * mm_idp, | 289 | extern long syscall_stub_data(struct mm_id * mm_idp, |
289 | unsigned long *data, int data_count, | 290 | unsigned long *data, int data_count, |
290 | void **addr, void **stub_addr); | 291 | void **addr, void **stub_addr); |
291 | extern int map(struct mm_id * mm_idp, unsigned long virt, | 292 | extern int map(struct mm_id * mm_idp, unsigned long virt, |
292 | unsigned long len, int r, int w, int x, int phys_fd, | 293 | unsigned long len, int r, int w, int x, int phys_fd, |
293 | unsigned long long offset, int done, void **data); | 294 | unsigned long long offset, int done, void **data); |
294 | extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, | 295 | extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, |
295 | int done, void **data); | 296 | int done, void **data); |
296 | extern int protect(struct mm_id * mm_idp, unsigned long addr, | 297 | extern int protect(struct mm_id * mm_idp, unsigned long addr, |
297 | unsigned long len, int r, int w, int x, int done, | 298 | unsigned long len, int r, int w, int x, int done, |
298 | void **data); | 299 | void **data); |
299 | 300 | ||
300 | /* skas/process.c */ | 301 | /* skas/process.c */ |
301 | extern int is_skas_winch(int pid, int fd, void *data); | 302 | extern int is_skas_winch(int pid, int fd, void *data); |
302 | extern int start_userspace(unsigned long stub_stack); | 303 | extern int start_userspace(unsigned long stub_stack); |
303 | extern int copy_context_skas0(unsigned long stack, int pid); | 304 | extern int copy_context_skas0(unsigned long stack, int pid); |
304 | extern void userspace(union uml_pt_regs *regs); | 305 | extern void userspace(union uml_pt_regs *regs); |
305 | extern void map_stub_pages(int fd, unsigned long code, | 306 | extern void map_stub_pages(int fd, unsigned long code, |
306 | unsigned long data, unsigned long stack); | 307 | unsigned long data, unsigned long stack); |
307 | extern void new_thread(void *stack, void **switch_buf_ptr, | 308 | extern void new_thread(void *stack, void **switch_buf_ptr, |
308 | void **fork_buf_ptr, void (*handler)(int)); | 309 | void **fork_buf_ptr, void (*handler)(int)); |
309 | extern void thread_wait(void *sw, void *fb); | 310 | extern void thread_wait(void *sw, void *fb); |
310 | extern void switch_threads(void *me, void *next); | 311 | extern void switch_threads(void *me, void *next); |
311 | extern int start_idle_thread(void *stack, void *switch_buf_ptr, | 312 | extern int start_idle_thread(void *stack, void *switch_buf_ptr, |
312 | void **fork_buf_ptr); | 313 | void **fork_buf_ptr); |
313 | extern void initial_thread_cb_skas(void (*proc)(void *), | 314 | extern void initial_thread_cb_skas(void (*proc)(void *), |
314 | void *arg); | 315 | void *arg); |
315 | extern void halt_skas(void); | 316 | extern void halt_skas(void); |
316 | extern void reboot_skas(void); | 317 | extern void reboot_skas(void); |
317 | 318 | ||
318 | /* irq.c */ | 319 | /* irq.c */ |
319 | extern int os_waiting_for_events(struct irq_fd *active_fds); | 320 | extern int os_waiting_for_events(struct irq_fd *active_fds); |
320 | extern int os_isatty(int fd); | 321 | extern int os_isatty(int fd); |
321 | extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds); | 322 | extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds); |
322 | extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, | 323 | extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, |
323 | struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2); | 324 | struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2); |
324 | extern void os_free_irq_later(struct irq_fd *active_fds, | 325 | extern void os_free_irq_later(struct irq_fd *active_fds, |
325 | int irq, void *dev_id); | 326 | int irq, void *dev_id); |
326 | extern int os_get_pollfd(int i); | 327 | extern int os_get_pollfd(int i); |
327 | extern void os_set_pollfd(int i, int fd); | 328 | extern void os_set_pollfd(int i, int fd); |
328 | extern void os_set_ioignore(void); | 329 | extern void os_set_ioignore(void); |
329 | extern void init_irq_signals(int on_sigstack); | 330 | extern void init_irq_signals(int on_sigstack); |
330 | 331 | ||
331 | /* sigio.c */ | 332 | /* sigio.c */ |
332 | extern void write_sigio_workaround(void); | 333 | extern void write_sigio_workaround(void); |
333 | extern int add_sigio_fd(int fd, int read); | 334 | extern int add_sigio_fd(int fd, int read); |
334 | extern int ignore_sigio_fd(int fd); | 335 | extern int ignore_sigio_fd(int fd); |
335 | 336 | ||
336 | /* skas/trap */ | 337 | /* skas/trap */ |
337 | extern void sig_handler_common_skas(int sig, void *sc_ptr); | 338 | extern void sig_handler_common_skas(int sig, void *sc_ptr); |
338 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); | 339 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); |
339 | 340 | ||
340 | #endif | 341 | #endif |
341 | 342 |
arch/um/include/sysdep-i386/tls.h
1 | #ifndef _SYSDEP_TLS_H | 1 | #ifndef _SYSDEP_TLS_H |
2 | #define _SYSDEP_TLS_H | 2 | #define _SYSDEP_TLS_H |
3 | 3 | ||
4 | # ifndef __KERNEL__ | 4 | # ifndef __KERNEL__ |
5 | 5 | ||
6 | /* Change name to avoid conflicts with the original one from <asm/ldt.h>, which | 6 | /* Change name to avoid conflicts with the original one from <asm/ldt.h>, which |
7 | * may be named user_desc (but in 2.4 and in header matching its API was named | 7 | * may be named user_desc (but in 2.4 and in header matching its API was named |
8 | * modify_ldt_ldt_s). */ | 8 | * modify_ldt_ldt_s). */ |
9 | 9 | ||
10 | typedef struct um_dup_user_desc { | 10 | typedef struct um_dup_user_desc { |
11 | unsigned int entry_number; | 11 | unsigned int entry_number; |
12 | unsigned int base_addr; | 12 | unsigned int base_addr; |
13 | unsigned int limit; | 13 | unsigned int limit; |
14 | unsigned int seg_32bit:1; | 14 | unsigned int seg_32bit:1; |
15 | unsigned int contents:2; | 15 | unsigned int contents:2; |
16 | unsigned int read_exec_only:1; | 16 | unsigned int read_exec_only:1; |
17 | unsigned int limit_in_pages:1; | 17 | unsigned int limit_in_pages:1; |
18 | unsigned int seg_not_present:1; | 18 | unsigned int seg_not_present:1; |
19 | unsigned int useable:1; | 19 | unsigned int useable:1; |
20 | } user_desc_t; | 20 | } user_desc_t; |
21 | 21 | ||
22 | # else /* __KERNEL__ */ | 22 | # else /* __KERNEL__ */ |
23 | 23 | ||
24 | # include <asm/ldt.h> | 24 | # include <asm/ldt.h> |
25 | typedef struct user_desc user_desc_t; | 25 | typedef struct user_desc user_desc_t; |
26 | 26 | ||
27 | # endif /* __KERNEL__ */ | 27 | # endif /* __KERNEL__ */ |
28 | |||
29 | #define GDT_ENTRY_TLS_MIN_I386 6 | ||
30 | #define GDT_ENTRY_TLS_MIN_X86_64 12 | ||
31 | |||
28 | #endif /* _SYSDEP_TLS_H */ | 32 | #endif /* _SYSDEP_TLS_H */ |
29 | 33 |
arch/um/include/user_util.h
1 | /* | 1 | /* |
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #ifndef __USER_UTIL_H__ | 6 | #ifndef __USER_UTIL_H__ |
7 | #define __USER_UTIL_H__ | 7 | #define __USER_UTIL_H__ |
8 | 8 | ||
9 | #include "sysdep/ptrace.h" | 9 | #include "sysdep/ptrace.h" |
10 | 10 | ||
11 | /* Copied from kernel.h */ | ||
12 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
13 | |||
11 | #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) | 14 | #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) |
12 | 15 | ||
13 | extern int mode_tt; | 16 | extern int mode_tt; |
14 | 17 | ||
15 | extern int grantpt(int __fd); | 18 | extern int grantpt(int __fd); |
16 | extern int unlockpt(int __fd); | 19 | extern int unlockpt(int __fd); |
17 | extern char *ptsname(int __fd); | 20 | extern char *ptsname(int __fd); |
18 | 21 | ||
19 | struct cpu_task { | 22 | struct cpu_task { |
20 | int pid; | 23 | int pid; |
21 | void *task; | 24 | void *task; |
22 | }; | 25 | }; |
23 | 26 | ||
24 | extern struct cpu_task cpu_tasks[]; | 27 | extern struct cpu_task cpu_tasks[]; |
25 | 28 | ||
26 | extern void (*sig_info[])(int, union uml_pt_regs *); | 29 | extern void (*sig_info[])(int, union uml_pt_regs *); |
27 | 30 | ||
28 | extern unsigned long low_physmem; | 31 | extern unsigned long low_physmem; |
29 | extern unsigned long high_physmem; | 32 | extern unsigned long high_physmem; |
30 | extern unsigned long uml_physmem; | 33 | extern unsigned long uml_physmem; |
31 | extern unsigned long uml_reserved; | 34 | extern unsigned long uml_reserved; |
32 | extern unsigned long end_vm; | 35 | extern unsigned long end_vm; |
33 | extern unsigned long start_vm; | 36 | extern unsigned long start_vm; |
34 | extern unsigned long long highmem; | 37 | extern unsigned long long highmem; |
35 | 38 | ||
36 | extern char host_info[]; | 39 | extern char host_info[]; |
37 | 40 | ||
38 | extern char saved_command_line[]; | 41 | extern char saved_command_line[]; |
39 | 42 | ||
40 | extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; | 43 | extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; |
41 | extern unsigned long _unprotected_end; | 44 | extern unsigned long _unprotected_end; |
42 | extern unsigned long brk_start; | 45 | extern unsigned long brk_start; |
43 | 46 | ||
44 | extern int pty_output_sigio; | 47 | extern int pty_output_sigio; |
45 | extern int pty_close_sigio; | 48 | extern int pty_close_sigio; |
46 | 49 | ||
47 | extern void *add_signal_handler(int sig, void (*handler)(int)); | 50 | extern void *add_signal_handler(int sig, void (*handler)(int)); |
48 | extern int linux_main(int argc, char **argv); | 51 | extern int linux_main(int argc, char **argv); |
49 | extern void set_cmdline(char *cmd); | 52 | extern void set_cmdline(char *cmd); |
50 | extern void input_cb(void (*proc)(void *), void *arg, int arg_len); | 53 | extern void input_cb(void (*proc)(void *), void *arg, int arg_len); |
51 | extern int get_pty(void); | 54 | extern int get_pty(void); |
52 | extern void *um_kmalloc(int size); | 55 | extern void *um_kmalloc(int size); |
53 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); | 56 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); |
54 | extern void do_exec(int old_pid, int new_pid); | 57 | extern void do_exec(int old_pid, int new_pid); |
55 | extern void tracer_panic(char *msg, ...); | 58 | extern void tracer_panic(char *msg, ...); |
56 | extern int detach(int pid, int sig); | 59 | extern int detach(int pid, int sig); |
57 | extern int attach(int pid); | 60 | extern int attach(int pid); |
58 | extern void kill_child_dead(int pid); | 61 | extern void kill_child_dead(int pid); |
59 | extern int cont(int pid); | 62 | extern int cont(int pid); |
60 | extern void check_sigio(void); | 63 | extern void check_sigio(void); |
61 | extern void arch_check_bugs(void); | 64 | extern void arch_check_bugs(void); |
62 | extern int cpu_feature(char *what, char *buf, int len); | 65 | extern int cpu_feature(char *what, char *buf, int len); |
63 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); | 66 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); |
64 | extern int arch_fixup(unsigned long address, void *sc_ptr); | 67 | extern int arch_fixup(unsigned long address, void *sc_ptr); |
65 | extern void arch_init_thread(void); | 68 | extern void arch_init_thread(void); |
66 | extern int raw(int fd); | 69 | extern int raw(int fd); |
67 | 70 | ||
68 | #endif | 71 | #endif |
69 | 72 |
arch/um/os-Linux/sys-i386/Makefile
1 | # | 1 | # |
2 | # Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 2 | # Copyright (C) 2000 Jeff Dike (jdike@karaya.com) |
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_MODE_SKAS) = registers.o | 6 | obj-$(CONFIG_MODE_SKAS) = registers.o tls.o |
7 | 7 | ||
8 | USER_OBJS := $(obj-y) | 8 | USER_OBJS := $(obj-y) |
9 | 9 | ||
10 | include arch/um/scripts/Makefile.rules | 10 | include arch/um/scripts/Makefile.rules |
11 | 11 |
arch/um/os-Linux/sys-i386/tls.c
File was created | 1 | #include <linux/unistd.h> | |
2 | #include "sysdep/tls.h" | ||
3 | #include "user_util.h" | ||
4 | |||
5 | static _syscall1(int, get_thread_area, user_desc_t *, u_info); | ||
6 | |||
7 | /* Checks whether host supports TLS, and sets *tls_min according to the value | ||
8 | * valid on the host. | ||
9 | * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ | ||
10 | void check_host_supports_tls(int *supports_tls, int *tls_min) { | ||
11 | /* Values for x86 and x86_64.*/ | ||
12 | int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; | ||
13 | int i; | ||
14 | |||
15 | for (i = 0; i < ARRAY_SIZE(val); i++) { | ||
16 | user_desc_t info; | ||
17 | info.entry_number = val[i]; | ||
18 | |||
19 | if (get_thread_area(&info) == 0) { | ||
20 | *tls_min = val[i]; | ||
21 | *supports_tls = 1; | ||
22 | return; | ||
23 | } else { | ||
24 | if (errno == EINVAL) | ||
25 | continue; | ||
26 | else if (errno == ENOSYS) | ||
27 | *supports_tls = 0; | ||
28 | return; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | *supports_tls = 0; | ||
33 | } | ||
34 |
arch/um/os-Linux/tls.c
1 | #include <errno.h> | 1 | #include <errno.h> |
2 | #include <sys/ptrace.h> | 2 | #include <sys/ptrace.h> |
3 | #include <asm/ldt.h> | 3 | #include <asm/ldt.h> |
4 | #include "sysdep/tls.h" | 4 | #include "sysdep/tls.h" |
5 | #include "uml-config.h" | 5 | #include "uml-config.h" |
6 | 6 | ||
7 | /* TLS support - we basically rely on the host's one.*/ | 7 | /* TLS support - we basically rely on the host's one.*/ |
8 | 8 | ||
9 | /* In TT mode, this should be called only by the tracing thread, and makes sense | 9 | /* In TT mode, this should be called only by the tracing thread, and makes sense |
10 | * only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally. | 10 | * only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally. |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #ifndef PTRACE_GET_THREAD_AREA | 14 | #ifndef PTRACE_GET_THREAD_AREA |
15 | #define PTRACE_GET_THREAD_AREA 25 | 15 | #define PTRACE_GET_THREAD_AREA 25 |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | #ifndef PTRACE_SET_THREAD_AREA | 18 | #ifndef PTRACE_SET_THREAD_AREA |
19 | #define PTRACE_SET_THREAD_AREA 26 | 19 | #define PTRACE_SET_THREAD_AREA 26 |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | int os_set_thread_area(user_desc_t *info, int pid) | 22 | int os_set_thread_area(user_desc_t *info, int pid) |
23 | { | 23 | { |
24 | int ret; | 24 | int ret; |
25 | 25 | ||
26 | ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, | 26 | ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, |
27 | (unsigned long) info); | 27 | (unsigned long) info); |
28 | if (ret < 0) | 28 | if (ret < 0) |
29 | ret = -errno; | 29 | ret = -errno; |
30 | return ret; | 30 | return ret; |
31 | } | 31 | } |
32 | 32 | ||
33 | #ifdef UML_CONFIG_MODE_SKAS | 33 | #ifdef UML_CONFIG_MODE_SKAS |
34 | 34 | ||
35 | int os_get_thread_area(user_desc_t *info, int pid) | 35 | int os_get_thread_area(user_desc_t *info, int pid) |
36 | { | 36 | { |
37 | int ret; | 37 | int ret; |
38 | 38 | ||
39 | ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, | 39 | ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, |
40 | (unsigned long) info); | 40 | (unsigned long) info); |
41 | if (ret < 0) | 41 | if (ret < 0) |
42 | ret = -errno; | 42 | ret = -errno; |
43 | return ret; | 43 | return ret; |
44 | } | 44 | } |
45 | 45 | ||
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | #ifdef UML_CONFIG_MODE_TT | 48 | #ifdef UML_CONFIG_MODE_TT |
49 | #include "linux/unistd.h" | 49 | #include "linux/unistd.h" |
50 | 50 | ||
51 | _syscall1(int, get_thread_area, user_desc_t *, u_info); | 51 | static _syscall1(int, get_thread_area, user_desc_t *, u_info); |
52 | _syscall1(int, set_thread_area, user_desc_t *, u_info); | 52 | static _syscall1(int, set_thread_area, user_desc_t *, u_info); |
53 | 53 | ||
54 | int do_set_thread_area_tt(user_desc_t *info) | 54 | int do_set_thread_area_tt(user_desc_t *info) |
55 | { | 55 | { |
56 | int ret; | 56 | int ret; |
57 | 57 | ||
58 | ret = set_thread_area(info); | 58 | ret = set_thread_area(info); |
59 | if (ret < 0) { | 59 | if (ret < 0) { |
60 | ret = -errno; | 60 | ret = -errno; |
61 | } | 61 | } |
62 | return ret; | 62 | return ret; |
63 | } | 63 | } |
64 | 64 | ||
65 | int do_get_thread_area_tt(user_desc_t *info) | 65 | int do_get_thread_area_tt(user_desc_t *info) |
66 | { | 66 | { |
67 | int ret; | 67 | int ret; |
68 | 68 | ||
69 | ret = get_thread_area(info); | 69 | ret = get_thread_area(info); |
70 | if (ret < 0) { | 70 | if (ret < 0) { |
71 | ret = -errno; | 71 | ret = -errno; |
72 | } | 72 | } |
73 | return ret; | 73 | return ret; |
74 | } | 74 | } |
75 | 75 | ||
76 | #endif /* UML_CONFIG_MODE_TT */ | 76 | #endif /* UML_CONFIG_MODE_TT */ |
77 | 77 |
arch/um/sys-i386/tls.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> | 2 | * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include "linux/config.h" | 6 | #include "linux/config.h" |
7 | #include "linux/kernel.h" | 7 | #include "linux/kernel.h" |
8 | #include "linux/sched.h" | 8 | #include "linux/sched.h" |
9 | #include "linux/slab.h" | 9 | #include "linux/slab.h" |
10 | #include "linux/types.h" | 10 | #include "linux/types.h" |
11 | #include "asm/uaccess.h" | 11 | #include "asm/uaccess.h" |
12 | #include "asm/ptrace.h" | 12 | #include "asm/ptrace.h" |
13 | #include "asm/segment.h" | 13 | #include "asm/segment.h" |
14 | #include "asm/smp.h" | 14 | #include "asm/smp.h" |
15 | #include "asm/desc.h" | 15 | #include "asm/desc.h" |
16 | #include "choose-mode.h" | 16 | #include "choose-mode.h" |
17 | #include "kern.h" | 17 | #include "kern.h" |
18 | #include "kern_util.h" | 18 | #include "kern_util.h" |
19 | #include "mode_kern.h" | 19 | #include "mode_kern.h" |
20 | #include "os.h" | 20 | #include "os.h" |
21 | #include "mode.h" | 21 | #include "mode.h" |
22 | 22 | ||
23 | #ifdef CONFIG_MODE_SKAS | 23 | #ifdef CONFIG_MODE_SKAS |
24 | #include "skas.h" | 24 | #include "skas.h" |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | /* If needed we can detect when it's uninitialized. */ | ||
28 | static int host_supports_tls = -1; | ||
29 | int host_gdt_entry_tls_min = -1; | ||
30 | |||
27 | #ifdef CONFIG_MODE_SKAS | 31 | #ifdef CONFIG_MODE_SKAS |
28 | int do_set_thread_area_skas(struct user_desc *info) | 32 | int do_set_thread_area_skas(struct user_desc *info) |
29 | { | 33 | { |
30 | int ret; | 34 | int ret; |
31 | u32 cpu; | 35 | u32 cpu; |
32 | 36 | ||
33 | cpu = get_cpu(); | 37 | cpu = get_cpu(); |
34 | ret = os_set_thread_area(info, userspace_pid[cpu]); | 38 | ret = os_set_thread_area(info, userspace_pid[cpu]); |
35 | put_cpu(); | 39 | put_cpu(); |
36 | return ret; | 40 | return ret; |
37 | } | 41 | } |
38 | 42 | ||
39 | int do_get_thread_area_skas(struct user_desc *info) | 43 | int do_get_thread_area_skas(struct user_desc *info) |
40 | { | 44 | { |
41 | int ret; | 45 | int ret; |
42 | u32 cpu; | 46 | u32 cpu; |
43 | 47 | ||
44 | cpu = get_cpu(); | 48 | cpu = get_cpu(); |
45 | ret = os_get_thread_area(info, userspace_pid[cpu]); | 49 | ret = os_get_thread_area(info, userspace_pid[cpu]); |
46 | put_cpu(); | 50 | put_cpu(); |
47 | return ret; | 51 | return ret; |
48 | } | 52 | } |
49 | #endif | 53 | #endif |
50 | 54 | ||
51 | /* | 55 | /* |
52 | * sys_get_thread_area: get a yet unused TLS descriptor index. | 56 | * sys_get_thread_area: get a yet unused TLS descriptor index. |
53 | * XXX: Consider leaving one free slot for glibc usage at first place. This must | 57 | * XXX: Consider leaving one free slot for glibc usage at first place. This must |
54 | * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else. | 58 | * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else. |
55 | * | 59 | * |
56 | * Also, this must be tested when compiling in SKAS mode with dinamic linking | 60 | * Also, this must be tested when compiling in SKAS mode with dinamic linking |
57 | * and running against NPTL. | 61 | * and running against NPTL. |
58 | */ | 62 | */ |
59 | static int get_free_idx(struct task_struct* task) | 63 | static int get_free_idx(struct task_struct* task) |
60 | { | 64 | { |
61 | struct thread_struct *t = &task->thread; | 65 | struct thread_struct *t = &task->thread; |
62 | int idx; | 66 | int idx; |
63 | 67 | ||
64 | if (!t->arch.tls_array) | 68 | if (!t->arch.tls_array) |
65 | return GDT_ENTRY_TLS_MIN; | 69 | return GDT_ENTRY_TLS_MIN; |
66 | 70 | ||
67 | for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) | 71 | for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) |
68 | if (!t->arch.tls_array[idx].present) | 72 | if (!t->arch.tls_array[idx].present) |
69 | return idx + GDT_ENTRY_TLS_MIN; | 73 | return idx + GDT_ENTRY_TLS_MIN; |
70 | return -ESRCH; | 74 | return -ESRCH; |
71 | } | 75 | } |
72 | 76 | ||
73 | static inline void clear_user_desc(struct user_desc* info) | 77 | static inline void clear_user_desc(struct user_desc* info) |
74 | { | 78 | { |
75 | /* Postcondition: LDT_empty(info) returns true. */ | 79 | /* Postcondition: LDT_empty(info) returns true. */ |
76 | memset(info, 0, sizeof(*info)); | 80 | memset(info, 0, sizeof(*info)); |
77 | 81 | ||
78 | /* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain | 82 | /* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain |
79 | * indeed an empty user_desc. | 83 | * indeed an empty user_desc. |
80 | */ | 84 | */ |
81 | info->read_exec_only = 1; | 85 | info->read_exec_only = 1; |
82 | info->seg_not_present = 1; | 86 | info->seg_not_present = 1; |
83 | } | 87 | } |
84 | 88 | ||
85 | #define O_FORCE 1 | 89 | #define O_FORCE 1 |
86 | 90 | ||
87 | static int load_TLS(int flags, struct task_struct *to) | 91 | static int load_TLS(int flags, struct task_struct *to) |
88 | { | 92 | { |
89 | int ret = 0; | 93 | int ret = 0; |
90 | int idx; | 94 | int idx; |
91 | 95 | ||
92 | for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) { | 96 | for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) { |
93 | struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; | 97 | struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; |
94 | 98 | ||
95 | /* Actually, now if it wasn't flushed it gets cleared and | 99 | /* Actually, now if it wasn't flushed it gets cleared and |
96 | * flushed to the host, which will clear it.*/ | 100 | * flushed to the host, which will clear it.*/ |
97 | if (!curr->present) { | 101 | if (!curr->present) { |
98 | if (!curr->flushed) { | 102 | if (!curr->flushed) { |
99 | clear_user_desc(&curr->tls); | 103 | clear_user_desc(&curr->tls); |
100 | curr->tls.entry_number = idx; | 104 | curr->tls.entry_number = idx; |
101 | } else { | 105 | } else { |
102 | WARN_ON(!LDT_empty(&curr->tls)); | 106 | WARN_ON(!LDT_empty(&curr->tls)); |
103 | continue; | 107 | continue; |
104 | } | 108 | } |
105 | } | 109 | } |
106 | 110 | ||
107 | if (!(flags & O_FORCE) && curr->flushed) | 111 | if (!(flags & O_FORCE) && curr->flushed) |
108 | continue; | 112 | continue; |
109 | 113 | ||
110 | ret = do_set_thread_area(&curr->tls); | 114 | ret = do_set_thread_area(&curr->tls); |
111 | if (ret) | 115 | if (ret) |
112 | goto out; | 116 | goto out; |
113 | 117 | ||
114 | curr->flushed = 1; | 118 | curr->flushed = 1; |
115 | } | 119 | } |
116 | out: | 120 | out: |
117 | return ret; | 121 | return ret; |
118 | } | 122 | } |
119 | 123 | ||
120 | /* Verify if we need to do a flush for the new process, i.e. if there are any | 124 | /* Verify if we need to do a flush for the new process, i.e. if there are any |
121 | * present desc's, only if they haven't been flushed. | 125 | * present desc's, only if they haven't been flushed. |
122 | */ | 126 | */ |
123 | static inline int needs_TLS_update(struct task_struct *task) | 127 | static inline int needs_TLS_update(struct task_struct *task) |
124 | { | 128 | { |
125 | int i; | 129 | int i; |
126 | int ret = 0; | 130 | int ret = 0; |
127 | 131 | ||
128 | for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { | 132 | for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { |
129 | struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; | 133 | struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; |
130 | 134 | ||
131 | /* Can't test curr->present, we may need to clear a descriptor | 135 | /* Can't test curr->present, we may need to clear a descriptor |
132 | * which had a value. */ | 136 | * which had a value. */ |
133 | if (curr->flushed) | 137 | if (curr->flushed) |
134 | continue; | 138 | continue; |
135 | ret = 1; | 139 | ret = 1; |
136 | break; | 140 | break; |
137 | } | 141 | } |
138 | return ret; | 142 | return ret; |
139 | } | 143 | } |
140 | 144 | ||
141 | /* On a newly forked process, the TLS descriptors haven't yet been flushed. So | 145 | /* On a newly forked process, the TLS descriptors haven't yet been flushed. So |
142 | * we mark them as such and the first switch_to will do the job. | 146 | * we mark them as such and the first switch_to will do the job. |
143 | */ | 147 | */ |
144 | void clear_flushed_tls(struct task_struct *task) | 148 | void clear_flushed_tls(struct task_struct *task) |
145 | { | 149 | { |
146 | int i; | 150 | int i; |
147 | 151 | ||
148 | for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { | 152 | for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { |
149 | struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; | 153 | struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; |
150 | 154 | ||
151 | /* Still correct to do this, if it wasn't present on the host it | 155 | /* Still correct to do this, if it wasn't present on the host it |
152 | * will remain as flushed as it was. */ | 156 | * will remain as flushed as it was. */ |
153 | if (!curr->present) | 157 | if (!curr->present) |
154 | continue; | 158 | continue; |
155 | 159 | ||
156 | curr->flushed = 0; | 160 | curr->flushed = 0; |
157 | } | 161 | } |
158 | } | 162 | } |
159 | 163 | ||
160 | /* This in SKAS0 does not need to be used, since we have different host | 164 | /* In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a |
161 | * processes. Nor will this need to be used when we'll add support to the host | 165 | * common host process. So this is needed in SKAS0 too. |
166 | * | ||
167 | * However, if each thread had a different host process (and this was discussed | ||
168 | * for SMP support) this won't be needed. | ||
169 | * | ||
170 | * And this will not need be used when (and if) we'll add support to the host | ||
162 | * SKAS patch. */ | 171 | * SKAS patch. */ |
172 | |||
163 | int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) | 173 | int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) |
164 | { | 174 | { |
175 | if (!host_supports_tls) | ||
176 | return 0; | ||
177 | |||
165 | /* We have no need whatsoever to switch TLS for kernel threads; beyond | 178 | /* We have no need whatsoever to switch TLS for kernel threads; beyond |
166 | * that, that would also result in us calling os_set_thread_area with | 179 | * that, that would also result in us calling os_set_thread_area with |
167 | * userspace_pid[cpu] == 0, which gives an error. */ | 180 | * userspace_pid[cpu] == 0, which gives an error. */ |
168 | if (likely(to->mm)) | 181 | if (likely(to->mm)) |
169 | return load_TLS(O_FORCE, to); | 182 | return load_TLS(O_FORCE, to); |
170 | 183 | ||
171 | return 0; | 184 | return 0; |
172 | } | 185 | } |
173 | 186 | ||
174 | int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) | 187 | int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) |
175 | { | 188 | { |
189 | if (!host_supports_tls) | ||
190 | return 0; | ||
191 | |||
176 | if (needs_TLS_update(to)) | 192 | if (needs_TLS_update(to)) |
177 | return load_TLS(0, to); | 193 | return load_TLS(0, to); |
178 | 194 | ||
179 | return 0; | 195 | return 0; |
180 | } | 196 | } |
181 | 197 | ||
182 | static int set_tls_entry(struct task_struct* task, struct user_desc *info, | 198 | static int set_tls_entry(struct task_struct* task, struct user_desc *info, |
183 | int idx, int flushed) | 199 | int idx, int flushed) |
184 | { | 200 | { |
185 | struct thread_struct *t = &task->thread; | 201 | struct thread_struct *t = &task->thread; |
186 | 202 | ||
187 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | 203 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) |
188 | return -EINVAL; | 204 | return -EINVAL; |
189 | 205 | ||
190 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info; | 206 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info; |
191 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1; | 207 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1; |
192 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed; | 208 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed; |
193 | 209 | ||
194 | return 0; | 210 | return 0; |
195 | } | 211 | } |
196 | 212 | ||
197 | int arch_copy_tls(struct task_struct *new) | 213 | int arch_copy_tls(struct task_struct *new) |
198 | { | 214 | { |
199 | struct user_desc info; | 215 | struct user_desc info; |
200 | int idx, ret = -EFAULT; | 216 | int idx, ret = -EFAULT; |
201 | 217 | ||
202 | if (copy_from_user(&info, | 218 | if (copy_from_user(&info, |
203 | (void __user *) UPT_ESI(&new->thread.regs.regs), | 219 | (void __user *) UPT_ESI(&new->thread.regs.regs), |
204 | sizeof(info))) | 220 | sizeof(info))) |
205 | goto out; | 221 | goto out; |
206 | 222 | ||
207 | ret = -EINVAL; | 223 | ret = -EINVAL; |
208 | if (LDT_empty(&info)) | 224 | if (LDT_empty(&info)) |
209 | goto out; | 225 | goto out; |
210 | 226 | ||
211 | idx = info.entry_number; | 227 | idx = info.entry_number; |
212 | 228 | ||
213 | ret = set_tls_entry(new, &info, idx, 0); | 229 | ret = set_tls_entry(new, &info, idx, 0); |
214 | out: | 230 | out: |
215 | return ret; | 231 | return ret; |
216 | } | 232 | } |
217 | 233 | ||
218 | /* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ | 234 | /* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ |
219 | static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx) | 235 | static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx) |
220 | { | 236 | { |
221 | struct thread_struct *t = &task->thread; | 237 | struct thread_struct *t = &task->thread; |
222 | 238 | ||
223 | if (!t->arch.tls_array) | 239 | if (!t->arch.tls_array) |
224 | goto clear; | 240 | goto clear; |
225 | 241 | ||
226 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | 242 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) |
227 | return -EINVAL; | 243 | return -EINVAL; |
228 | 244 | ||
229 | if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present) | 245 | if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present) |
230 | goto clear; | 246 | goto clear; |
231 | 247 | ||
232 | *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls; | 248 | *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls; |
233 | 249 | ||
234 | out: | 250 | out: |
235 | /* Temporary debugging check, to make sure that things have been | 251 | /* Temporary debugging check, to make sure that things have been |
236 | * flushed. This could be triggered if load_TLS() failed. | 252 | * flushed. This could be triggered if load_TLS() failed. |
237 | */ | 253 | */ |
238 | if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { | 254 | if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { |
239 | printk(KERN_ERR "get_tls_entry: task with pid %d got here " | 255 | printk(KERN_ERR "get_tls_entry: task with pid %d got here " |
240 | "without flushed TLS.", current->pid); | 256 | "without flushed TLS.", current->pid); |
241 | } | 257 | } |
242 | 258 | ||
243 | return 0; | 259 | return 0; |
244 | clear: | 260 | clear: |
245 | /* When the TLS entry has not been set, the values read to user in the | 261 | /* When the TLS entry has not been set, the values read to user in the |
246 | * tls_array are 0 (because it's cleared at boot, see | 262 | * tls_array are 0 (because it's cleared at boot, see |
247 | * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that. | 263 | * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that. |
248 | */ | 264 | */ |
249 | clear_user_desc(info); | 265 | clear_user_desc(info); |
250 | info->entry_number = idx; | 266 | info->entry_number = idx; |
251 | goto out; | 267 | goto out; |
252 | } | 268 | } |
253 | 269 | ||
254 | asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) | 270 | asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) |
255 | { | 271 | { |
256 | struct user_desc info; | 272 | struct user_desc info; |
257 | int idx, ret; | 273 | int idx, ret; |
258 | 274 | ||
275 | if (!host_supports_tls) | ||
276 | return -ENOSYS; | ||
277 | |||
259 | if (copy_from_user(&info, user_desc, sizeof(info))) | 278 | if (copy_from_user(&info, user_desc, sizeof(info))) |
260 | return -EFAULT; | 279 | return -EFAULT; |
261 | 280 | ||
262 | idx = info.entry_number; | 281 | idx = info.entry_number; |
263 | 282 | ||
264 | if (idx == -1) { | 283 | if (idx == -1) { |
265 | idx = get_free_idx(current); | 284 | idx = get_free_idx(current); |
266 | if (idx < 0) | 285 | if (idx < 0) |
267 | return idx; | 286 | return idx; |
268 | info.entry_number = idx; | 287 | info.entry_number = idx; |
269 | /* Tell the user which slot we chose for him.*/ | 288 | /* Tell the user which slot we chose for him.*/ |
270 | if (put_user(idx, &user_desc->entry_number)) | 289 | if (put_user(idx, &user_desc->entry_number)) |
271 | return -EFAULT; | 290 | return -EFAULT; |
272 | } | 291 | } |
273 | 292 | ||
274 | ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info); | 293 | ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info); |
275 | if (ret) | 294 | if (ret) |
276 | return ret; | 295 | return ret; |
277 | return set_tls_entry(current, &info, idx, 1); | 296 | return set_tls_entry(current, &info, idx, 1); |
278 | } | 297 | } |
279 | 298 | ||
280 | /* | 299 | /* |
281 | * Perform set_thread_area on behalf of the traced child. | 300 | * Perform set_thread_area on behalf of the traced child. |
282 | * Note: error handling is not done on the deferred load, and this differ from | 301 | * Note: error handling is not done on the deferred load, and this differ from |
283 | * i386. However the only possible error are caused by bugs. | 302 | * i386. However the only possible error are caused by bugs. |
284 | */ | 303 | */ |
285 | int ptrace_set_thread_area(struct task_struct *child, int idx, | 304 | int ptrace_set_thread_area(struct task_struct *child, int idx, |
286 | struct user_desc __user *user_desc) | 305 | struct user_desc __user *user_desc) |
287 | { | 306 | { |
288 | struct user_desc info; | 307 | struct user_desc info; |
289 | 308 | ||
309 | if (!host_supports_tls) | ||
310 | return -EIO; | ||
311 | |||
290 | if (copy_from_user(&info, user_desc, sizeof(info))) | 312 | if (copy_from_user(&info, user_desc, sizeof(info))) |
291 | return -EFAULT; | 313 | return -EFAULT; |
292 | 314 | ||
293 | return set_tls_entry(child, &info, idx, 0); | 315 | return set_tls_entry(child, &info, idx, 0); |
294 | } | 316 | } |
295 | 317 | ||
296 | asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc) | 318 | asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc) |
297 | { | 319 | { |
298 | struct user_desc info; | 320 | struct user_desc info; |
299 | int idx, ret; | 321 | int idx, ret; |
300 | 322 | ||
323 | if (!host_supports_tls) | ||
324 | return -ENOSYS; | ||
325 | |||
301 | if (get_user(idx, &user_desc->entry_number)) | 326 | if (get_user(idx, &user_desc->entry_number)) |
302 | return -EFAULT; | 327 | return -EFAULT; |
303 | 328 | ||
304 | ret = get_tls_entry(current, &info, idx); | 329 | ret = get_tls_entry(current, &info, idx); |
305 | if (ret < 0) | 330 | if (ret < 0) |
306 | goto out; | 331 | goto out; |
307 | 332 | ||
308 | if (copy_to_user(user_desc, &info, sizeof(info))) | 333 | if (copy_to_user(user_desc, &info, sizeof(info))) |
309 | ret = -EFAULT; | 334 | ret = -EFAULT; |
310 | 335 | ||
311 | out: | 336 | out: |
312 | return ret; | 337 | return ret; |
313 | } | 338 | } |
314 | 339 | ||
315 | /* | 340 | /* |
316 | * Perform get_thread_area on behalf of the traced child. | 341 | * Perform get_thread_area on behalf of the traced child. |
317 | */ | 342 | */ |
318 | int ptrace_get_thread_area(struct task_struct *child, int idx, | 343 | int ptrace_get_thread_area(struct task_struct *child, int idx, |
319 | struct user_desc __user *user_desc) | 344 | struct user_desc __user *user_desc) |
320 | { | 345 | { |
321 | struct user_desc info; | 346 | struct user_desc info; |
322 | int ret; | 347 | int ret; |
323 | 348 | ||
349 | if (!host_supports_tls) | ||
350 | return -EIO; | ||
351 | |||
324 | ret = get_tls_entry(child, &info, idx); | 352 | ret = get_tls_entry(child, &info, idx); |
325 | if (ret < 0) | 353 | if (ret < 0) |
326 | goto out; | 354 | goto out; |
327 | 355 | ||
328 | if (copy_to_user(user_desc, &info, sizeof(info))) | 356 | if (copy_to_user(user_desc, &info, sizeof(info))) |
329 | ret = -EFAULT; | 357 | ret = -EFAULT; |
330 | out: | 358 | out: |
331 | return ret; | 359 | return ret; |
332 | } | 360 | } |
361 | |||
362 | |||
363 | /* XXX: This part is probably common to i386 and x86-64. Don't create a common | ||
364 | * file for now, do that when implementing x86-64 support.*/ | ||
365 | static int __init __setup_host_supports_tls(void) { | ||
366 | check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); | ||
367 | if (host_supports_tls) { | ||
368 | printk(KERN_INFO "Host TLS support detected\n"); | ||
369 | printk(KERN_INFO "Detected host type: "); | ||
370 | switch (host_gdt_entry_tls_min) { | ||
371 | case GDT_ENTRY_TLS_MIN_I386: | ||
372 | printk("i386\n"); | ||
373 | break; | ||
374 | case GDT_ENTRY_TLS_MIN_X86_64: | ||
375 | printk("x86_64\n"); | ||
376 | break; | ||
377 | } | ||
378 | } else | ||
379 | printk(KERN_ERR " Host TLS support NOT detected! " | ||
380 | "TLS support inside UML will not work\n"); | ||
381 | return 1; | ||
382 | } | ||
383 | |||
384 | __initcall(__setup_host_supports_tls); | ||
333 | 385 |
include/asm-um/segment.h
1 | #ifndef __UM_SEGMENT_H | 1 | #ifndef __UM_SEGMENT_H |
2 | #define __UM_SEGMENT_H | 2 | #define __UM_SEGMENT_H |
3 | 3 | ||
4 | #include "asm/arch/segment.h" | 4 | extern int host_gdt_entry_tls_min; |
5 | |||
6 | #define GDT_ENTRY_TLS_ENTRIES 3 | ||
7 | #define GDT_ENTRY_TLS_MIN host_gdt_entry_tls_min | ||
8 | #define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1) | ||
5 | 9 | ||
6 | #endif | 10 | #endif |
7 | 11 |