Commit | Line | Data |
feb33499 |
1 | |
2 | /* |
3 | * gcc long pointer support code for HPPA. |
4 | * Copyright 1998, DIS International, Ltd. |
5 | * Permission is granted to use this code under the GNU LIBRARY GENERAL |
6 | * PUBLIC LICENSE, Version 2, June 1991. |
7 | */ |
8 | typedef struct { |
9 | int spaceid; |
10 | unsigned int offset; |
11 | } LONGPOINTER, longpointer; |
12 | |
13 | /* |
14 | * gcc long pointer support code for HPPA. |
15 | * Copyright 1998, DIS International, Ltd. |
16 | * Permission is granted to use this code under the GNU LIBRARY GENERAL |
17 | * PUBLIC LICENSE, Version 2, June 1991. |
18 | */ |
19 | |
20 | int __perl_mpe_getspaceid(void *source) |
21 | { |
22 | int val; |
23 | /* |
24 | * Given the short pointer, determine it's space ID. |
25 | */ |
26 | |
27 | /* |
28 | * The colons separate output from input parameters. In this case, |
29 | * the output of the instruction (output indicated by the "=" in the |
30 | * constraint) is to a memory location (indicated by the "m"). The |
31 | * input constraint indicates that the source to the instruction |
32 | * is a register reference (indicated by the "r"). |
33 | * The general format is: |
34 | * asm("<instruction template>" : <output> : <input> : <clobbers>); |
35 | * where <output> and <input> are: |
36 | * "<constraint>" (<token>) |
37 | * <instruction template> is the PA-RISC instruction in template fmt. |
38 | * <clobbers> indicates those registers clobbered by the instruction |
39 | * and provides hints to the optimizer. |
40 | * |
41 | * Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html |
42 | */ |
43 | asm volatile ( |
44 | "comiclr,= 0,%1,%%r28; |
45 | ldsid (%%r0,%1),%%r28; |
46 | stw %%r28, %0" |
47 | : "=m" (val) // Output to val |
48 | : "r" (source) // Source must be gen reg |
49 | : "%r28"); // Clobbers %r28 |
50 | return (val); |
51 | }; |
52 | |
53 | LONGPOINTER __perl_mpe_longaddr(void *source) |
54 | { |
55 | LONGPOINTER lptr; |
56 | /* |
57 | * Return the long pointer for the address in sr5 space. |
58 | */ |
59 | |
60 | asm volatile ( |
61 | "comiclr,= 0,%2,%%r28; |
62 | ldsid (%%r0,%2),%%r28; |
63 | stw %%r28, %0; |
64 | stw %2, %1" |
65 | : "=m" (lptr.spaceid), |
66 | "=m" (lptr.offset) // Store to lptr |
67 | : "r" (source) // Source must be gen reg |
68 | : "%r28"); // Clobbers %r28 |
69 | return (lptr); |
70 | }; |
71 | |
72 | LONGPOINTER __perl_mpe_addtopointer(LONGPOINTER source, // %r26 == source offset |
73 | // %r25 == source space |
74 | int len) // %r24 == length in bytes |
75 | { |
76 | /* |
77 | * Increment a longpointer. |
78 | */ |
79 | |
80 | asm volatile ( |
81 | "copy %0,%%r28; // copy space to r28 |
82 | add %1,%2,%%r29" // Increment the pointer |
83 | : // No output |
84 | : "r" (source.spaceid), // Source address |
85 | "r" (source.offset), |
86 | "r" (len) // Length |
87 | : "%r28", // Clobbers |
88 | "%r29"); |
89 | }; |
90 | |
91 | void __perl_mpe_longmove(int len, // %r26 == byte length |
92 | LONGPOINTER source, // %r23 == source space, %r24 == off |
93 | LONGPOINTER target) // sp-#56 == target space, sp-#52== off |
94 | { |
95 | /* |
96 | * Move data between two buffers in long pointer space. |
97 | */ |
98 | |
99 | asm volatile ( |
100 | ".import $$lr_unk_unk_long,MILLICODE; |
101 | mtsp %0,%%sr1; // copy source space to sr1 |
102 | copy %1,%%r26; // load source offset to r26 |
103 | copy %4,%%r24; // load length to r24 |
104 | copy %3,%%r25; // load target offset to r25 |
105 | bl $$lr_unk_unk_long,%%r31; // start branch to millicode |
106 | mtsp %2,%%sr2" // copy target space to sr2 |
107 | : // No output |
108 | : "r" (source.spaceid), // Source address |
109 | "r" (source.offset), |
110 | "r" (target.spaceid), // Target address |
111 | "r" (target.offset), |
112 | "r" (len) // Byte length |
113 | : "%r1", // Clobbers |
114 | "%r24", |
115 | "%r25", |
116 | "%r26", |
117 | "%r31"); |
118 | }; |
119 | |
120 | int __perl_mpe_longpeek(LONGPOINTER source) |
121 | { |
122 | /* |
123 | * Fetch the int in long pointer space. |
124 | */ |
125 | unsigned int val; |
126 | |
127 | asm volatile ( |
128 | "mtsp %1, %%sr1; |
129 | copy %2, %%r28; |
130 | ldw 0(%%sr1, %%r28), %%r28; |
131 | stw %%r28, %0" |
132 | : "=m" (val) // Output val |
133 | : "r" (source.spaceid), // Source space ID |
134 | "r" (source.offset) // Source offset |
135 | : "%r28"); // Clobbers %r28 |
136 | |
137 | return (val); |
138 | }; |
139 | |
140 | void __perl_mpe_longpoke(LONGPOINTER target, // %r25 == spaceid, %r26 == offset |
141 | unsigned int val) // %r24 == value |
142 | { |
143 | /* |
144 | * Store the val into long pointer space. |
145 | */ |
146 | asm volatile ( |
147 | "mtsp %0,%%sr1; |
148 | copy %1, %%r28; |
149 | stw %2, 0(%%sr1, %%r28)" |
150 | : // No output |
151 | : "r" (target.spaceid), // Target space ID |
152 | "r" (target.offset), // Target offset |
153 | "r" (val) // Value to store |
154 | : "%r28" // Clobbers %r28 |
155 | ); // Copy space to %sr1 |
156 | }; |
157 | |
158 | void __perl_mpe_move_fast(int len, // %r26 == byte length |
159 | void *source, // %r25 == source addr |
160 | void *target) // %r24 == target addr |
161 | { |
162 | /* |
163 | * Move using short pointers. |
164 | */ |
165 | asm volatile ( |
166 | ".import $$lr_unk_unk,MILLICODE; |
167 | copy %1, %%r26; // Move source addr into pos |
168 | copy %2, %%r25; // Move target addr into pos |
169 | bl $$lr_unk_unk,%%r31; // Start branch to millicode |
170 | copy %0, %%r24" // Move length into position |
171 | : // No output |
172 | : "r" (len), // Byte length |
173 | "r" (source), // Source address |
174 | "r" (target) // Target address |
175 | : "%r24", // Clobbers |
176 | "%r25", |
177 | "%r26", |
178 | "%r31"); |
179 | }; |
180 | |
181 | /* |
182 | * ftruncate - set file size, BSD Style |
183 | * |
184 | * shortens or enlarges the file as neeeded |
185 | * uses some undocumented locking call. It is known to work on SCO unix, |
186 | * other vendors should try. |
187 | * The #error directive prevents unsupported OSes |
188 | */ |
189 | |
190 | #include <unistd.h> |
191 | #include <errno.h> |
192 | #include <fcntl.h> |
193 | #include <stdio.h> |
194 | #include <mpe.h> |
195 | |
196 | extern void FCONTROL(short, short, longpointer); |
197 | extern void PRINTFILEINFO(int); |
198 | |
199 | int ftruncate(int fd, long wantsize); |
200 | |
201 | int ftruncate(int fd, long wantsize) { |
202 | |
203 | int ccode_return,dummy=0; |
204 | |
205 | if (lseek(fd, wantsize, SEEK_SET) < 0) { |
206 | return (-1); |
207 | } |
208 | |
209 | FCONTROL(_mpe_fileno(fd),6,__perl_mpe_longaddr(&dummy)); /* Write new EOF */ |
210 | if ((ccode_return=ccode()) != CCE) { |
211 | fprintf(stderr,"MPE ftruncate failed, ccode=%d, wantsize=%ld\n",ccode_return,wantsize); |
212 | PRINTFILEINFO(_mpe_fileno(fd)); |
213 | errno = ESYSERR; |
214 | return (-1); |
215 | } |
216 | |
217 | return (0); |
218 | } |
219 | |
220 | /* |
221 | wrapper for truncate(): |
222 | |
223 | truncate() is UNIX, not POSIX. |
224 | |
225 | This function requires ftruncate(). |
226 | |
227 | |
228 | |
229 | NAME |
230 | truncate - |
231 | |
232 | SYNOPSIS |
233 | #include <unistd.h> |
234 | |
235 | int truncate(const char *pathname, off_t length); |
236 | |
237 | Returns: 0 if OK, -1 on error |
238 | |
239 | from: Stevens' Advanced Programming in the UNIX Environment, p. 92 |
240 | |
241 | |
242 | |
243 | ERRORS |
244 | EACCES |
245 | EBADF |
246 | EDQUOT (not POSIX) <- not implemented here |
247 | EFAULT |
248 | EINVAL |
249 | EISDIR |
250 | ELOOP (not POSIX) <- not implemented here |
251 | ENAMETOOLONG |
252 | ENOTDIR |
253 | EROFS |
254 | ETXTBSY (not POSIX) <- not implemented here |
255 | |
256 | from: HP-UX man page |
257 | |
258 | |
259 | |
260 | Compile directives: |
261 | PRINT_ERROR - make this function print an error message to stderr |
262 | */ |
263 | |
264 | #ifndef _POSIX_SOURCE |
265 | # define _POSIX_SOURCE |
266 | #endif |
267 | |
268 | #include <sys/types.h> /* off_t, required by open() */ |
269 | #include <sys/stat.h> /* required by open() */ |
270 | #include <fcntl.h> /* open() */ |
271 | #include <unistd.h> /* close() */ |
272 | #include <stdio.h> /* perror(), sprintf() */ |
273 | |
274 | |
275 | |
276 | int |
277 | truncate(const char *pathname, off_t length) |
278 | { |
279 | int fd; |
280 | #ifdef PRINT_ERROR |
281 | char error_msg[80+1]; |
282 | #endif |
283 | |
284 | if (length == 0) |
285 | { |
286 | if ( (fd = open(pathname, O_WRONLY | O_TRUNC)) < 0) |
287 | { |
288 | /* errno already set */ |
289 | #ifdef PRINT_ERROR |
290 | sprintf(error_msg, |
291 | "truncate(): open(%s, O_WRONLY | OTRUNC)\0", |
292 | pathname); |
293 | perror(error_msg); |
294 | #endif |
295 | return -1; |
296 | } |
297 | } |
298 | else |
299 | { |
300 | if ( (fd = open(pathname, O_WRONLY)) < 0) |
301 | { |
302 | /* errno already set */ |
303 | #ifdef PRINT_ERROR |
304 | sprintf(error_msg, |
305 | "truncate(): open(%s, O_WRONLY)\0", |
306 | pathname); |
307 | perror(error_msg); |
308 | #endif |
309 | return -1; |
310 | } |
311 | |
312 | if (ftruncate(fd, length) < 0) |
313 | { |
314 | /* errno already set */ |
315 | #ifdef PRINT_ERROR |
316 | perror("truncate(): ftruncate()"); |
317 | #endif |
318 | return -1; |
319 | } |
320 | } |
321 | |
322 | if (close(fd) < 0) |
323 | { |
324 | /* errno already set */ |
325 | #ifdef PRINT_ERROR |
326 | perror("truncate(): close()"); |
327 | #endif |
328 | return -1; |
329 | } |
330 | |
331 | return 0; |
332 | } /* truncate() */ |
333 | |
334 | /* |
335 | wrapper for gettimeofday(): |
336 | gettimeofday() is UNIX, not POSIX. |
337 | gettimeofday() is a BSD function. |
338 | |
339 | |
340 | |
341 | NAME |
342 | gettimeofday - |
343 | |
344 | SYNOPSIS |
345 | #include <sys/time.h> |
346 | |
347 | int gettimeofday(struct timeval *tp, struct timezone *tzp); |
348 | |
349 | DESCRIPTION |
350 | This function returns seconds and microseconds since midnight |
351 | January 1, 1970. The microseconds is actually only accurate to |
352 | the millisecond. |
353 | |
354 | Note: To pick up the definitions of structs timeval and timezone |
355 | from the <time.h> include file, the directive |
356 | _SOCKET_SOURCE must be used. |
357 | |
358 | RETURN VALUE |
359 | A 0 return value indicates that the call succeeded. A -1 return |
360 | value indicates an error occurred; errno is set to indicate the |
361 | error. |
362 | |
363 | ERRORS |
364 | EFAULT not implemented |
365 | |
366 | Changes: |
367 | 2-91 DR. Created. |
368 | */ |
369 | |
370 | |
371 | /* need _SOCKET_SOURCE to pick up structs timeval and timezone in time.h */ |
372 | #ifndef _SOCKET_SOURCE |
373 | # define _SOCKET_SOURCE |
374 | #endif |
375 | |
376 | #include <time.h> /* structs timeval & timezone, |
377 | difftime(), localtime(), mktime(), time() */ |
378 | #include <sys/time.h> /* gettimeofday() */ |
379 | |
380 | extern int TIMER(); |
381 | |
382 | |
383 | |
384 | #ifdef __STDC__ |
385 | int gettimeofday( struct timeval *tp, struct timezone *tpz ) |
386 | #else |
387 | int gettimeofday( tp, tpz ) |
388 | struct timeval *tp; |
389 | struct timezone *tpz; |
390 | #endif |
391 | { |
392 | static unsigned long basetime = 0; |
393 | static int dsttime = 0; |
394 | static int minuteswest = 0; |
395 | static int oldtime = 0; |
396 | register int newtime; |
397 | |
398 | |
399 | /*-------------------------------------------------------------------*/ |
400 | /* Setup a base from which all future time will be computed. */ |
401 | /*-------------------------------------------------------------------*/ |
402 | if ( basetime == 0 ) |
403 | { |
404 | time_t gmt_time; |
405 | time_t loc_time; |
406 | struct tm *loc_time_tm; |
407 | |
408 | gmt_time = time( NULL ); |
409 | loc_time_tm = localtime( &gmt_time ) ; |
410 | loc_time = mktime( loc_time_tm ); |
411 | |
412 | oldtime = TIMER(); |
413 | basetime = (unsigned long) ( loc_time - (oldtime/1000) ); |
414 | |
415 | /*----------------------------------------------------------------*/ |
416 | /* The calling process must be restarted if timezone or dst */ |
417 | /* changes. */ |
418 | /*----------------------------------------------------------------*/ |
419 | minuteswest = (int) (difftime( loc_time, gmt_time ) / 60); |
420 | dsttime = loc_time_tm->tm_isdst; |
421 | } |
422 | |
423 | /*-------------------------------------------------------------------*/ |
424 | /* Get the new time value. The timer value rolls over every 24 days, */ |
425 | /* so if the delta is negative, the basetime value is adjusted. */ |
426 | /*-------------------------------------------------------------------*/ |
427 | newtime = TIMER(); |
428 | if ( newtime < oldtime ) basetime += 2073600; |
429 | oldtime = newtime; |
430 | |
431 | /*-------------------------------------------------------------------*/ |
432 | /* Return the timestamp info. */ |
433 | /*-------------------------------------------------------------------*/ |
434 | tp->tv_sec = basetime + newtime/1000; |
435 | tp->tv_usec = (newtime%1000) * 1000; /* only accurate to milli */ |
436 | if (tpz) |
437 | { |
438 | tpz->tz_minuteswest = minuteswest; |
439 | tpz->tz_dsttime = dsttime; |
440 | } |
441 | |
442 | return 0; |
443 | |
444 | } /* gettimeofday() */ |