3 $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/os-common.c,v 1.33 2010/12/22 02:12:52 rtoy Exp $
5 This code was written as part of the CMU Common Lisp project at
6 Carnegie Mellon University, and has been placed in the public domain.
16 #include "internals.h"
23 #include "interrupt.h"
25 /* Except for os_zero, these routines are only called by Lisp code. These
26 routines may also be replaced by os-dependent versions instead. See
27 hpux-os.c for some useful restrictions on actual usage. */
30 os_zero(os_vm_address_t addr, os_vm_size_t length)
32 os_vm_address_t block_start;
33 os_vm_size_t block_size;
36 fprintf(stderr, ";;; os_zero: addr: 0x%08x, len: 0x%08x\n", addr, length);
39 block_start = os_round_up_to_page(addr);
41 length -= block_start - addr;
42 block_size = os_trunc_size_to_page(length);
44 if (block_start > addr)
45 memset((char *) addr, 0, block_start - addr);
46 if (block_size < length)
47 memset((char *) block_start + block_size, 0, length - block_size);
49 if (block_size != 0) {
50 /* Now deallocate and allocate the block so that it */
51 /* faults in zero-filled. */
53 os_invalidate(block_start, block_size);
54 addr = os_validate(block_start, block_size);
56 if (addr == NULL || addr != block_start)
57 fprintf(stderr, "os_zero: block moved, 0x%p ==> 0x%8p!\n",
58 (void *) block_start, (void *) addr);
63 os_allocate(os_vm_size_t len)
65 return os_validate((os_vm_address_t) NULL, len);
69 os_allocate_at(os_vm_address_t addr, os_vm_size_t len)
71 return os_validate(addr, len);
75 os_deallocate(os_vm_address_t addr, os_vm_size_t len)
77 os_invalidate(addr, len);
80 /* This function once tried to grow the chunk by asking os_validate if the
81 space was available, but this really only works under Mach. */
84 os_reallocate(os_vm_address_t addr, os_vm_size_t old_len, os_vm_size_t len)
86 addr = os_trunc_to_page(addr);
87 len = os_round_up_size_to_page(len);
88 old_len = os_round_up_size_to_page(old_len);
91 return os_allocate(len);
93 long len_diff = len - old_len;
96 os_invalidate(addr + len, -len_diff);
99 os_vm_address_t new = os_allocate(len);
102 memcpy((char *) new, (char *) addr, old_len);
103 os_invalidate(addr, old_len);
120 os_set_errno(int value)
122 return errno = value;
134 LINKAGE_CODE_TYPE = 1,
135 LINKAGE_DATA_TYPE = 2
139 /* These declarations are lies. They actually take args, but are
140 never called by C. Only by Lisp */
141 extern void resolve_linkage_tramp(void);
142 extern void call_into_c(void);
145 #define LINKAGE_DATA_ENTRY_SIZE 3
150 convert_lisp_string(char* c_string, void* lisp_string, int len)
154 * FIXME: Unicode hack to convert Lisp 16-bit string to 8-bit string
155 * by lopping off the high bits.
159 unsigned short int* wide_string = (unsigned short int*) lisp_string;
161 for (k = 0; k < len; ++k) {
162 c_string[k] = (wide_string[k]) & 0xff;
166 strcpy(c_string, lisp_string);
173 os_foreign_linkage_init(void)
176 lispobj linkage_data_obj = SymbolValue(LINKAGE_TABLE_DATA);
177 struct array *linkage_data = 0;
179 struct vector *data_vector = 0;
182 linkage_data = (struct array *) PTR(linkage_data_obj);
183 table_size = fixnum_value(linkage_data->fill_pointer);
184 data_vector = (struct vector *) PTR(linkage_data->data);
185 for (i = 0; i < table_size; i += LINKAGE_DATA_ENTRY_SIZE) {
186 struct vector *symbol_name
187 = (struct vector *) PTR(data_vector->data[i]);
188 long type = fixnum_value(data_vector->data[i + 1]);
189 lispobj lib_list = data_vector->data[i + 2];
190 /* FIXME: 1000 may not be long enough. Add checks to make sure it's ok!!!!*/
191 char c_symbol_name[1000];
193 * Verify the "known" entries. This had better match what
194 * init-foreign-linkage in new-genesis does!
197 convert_lisp_string(c_symbol_name, symbol_name->data, (symbol_name->length >> 2));
200 fprintf(stderr, "i =%2d: %s\n", i, c_symbol_name);
203 unsigned short int* wide_string;
205 fprintf(stderr, " symbol_name->data = ");
207 wide_string = (unsigned short int *) symbol_name->data;
209 for (k = 0; k < (symbol_name->length >> 2); ++k) {
210 fprintf(stderr, "%4x ", wide_string[k]);
212 fprintf(stderr, "\n");
217 if (type != LINKAGE_CODE_TYPE || strcmp(c_symbol_name, "call_into_c")) {
218 fprintf(stderr, "linkage_data is %s but expected call_into_c\n",
219 (char *) symbol_name->data);
220 lose("First element of linkage_data is bogus.\n");
222 arch_make_linkage_entry(i, (void*) call_into_c, 1);
223 #elif (defined(DARWIN) && defined(__ppc__))
224 if (type != 1 || strcmp(c_symbol_name, "_call_into_c")) {
225 fprintf(stderr, "linkage_data is %s but expected call_into_c\n",
226 (char *) c_symbol_name);
227 lose("First element of linkage_data is bogus.\n");
229 arch_make_linkage_entry(i, &call_into_c, 1);
231 if (type != LINKAGE_CODE_TYPE || strcmp(c_symbol_name,
232 "resolve_linkage_tramp")) {
234 "linkage_data is %s but expected resolve_linkage_tramp\n",
235 (char *) c_symbol_name);
236 lose("First element of linkage_data is bogus.\n");
238 arch_make_linkage_entry(i, (void *) &resolve_linkage_tramp, 1);
242 if (type == LINKAGE_DATA_TYPE && lib_list == NIL) {
243 void *target_addr = os_dlsym(c_symbol_name, NIL);
248 unsigned short int* wide_string;
250 fprintf(stderr, "c_symbol_name = `%s'\n", c_symbol_name);
251 fprintf(stderr, "symbol_name->data = \n");
253 wide_string = (unsigned short int *) symbol_name->data;
255 for (k = 0; k < (symbol_name->length >> 2); ++k) {
256 fprintf(stderr, "%4x ", wide_string[k]);
258 fprintf(stderr, "\n");
260 lose("%s is not defined.\n", c_symbol_name);
262 arch_make_linkage_entry(i / LINKAGE_DATA_ENTRY_SIZE, target_addr,
265 arch_make_lazy_linkage(i / LINKAGE_DATA_ENTRY_SIZE);
269 #endif /* LINKAGE_TABLE */
272 /* At the second stage of initialization, after Lisp has dlopened all
273 needed shared libraries, go back through the table and initialize
277 os_resolve_data_linkage(void)
280 lispobj linkage_data_obj = SymbolValue(LINKAGE_TABLE_DATA);
281 struct array *linkage_data = 0;
283 struct vector *data_vector = 0;
286 linkage_data = (struct array *) PTR(linkage_data_obj);
287 table_size = fixnum_value(linkage_data->fill_pointer);
288 data_vector = (struct vector *) PTR(linkage_data->data);
289 for (i = 0; i < table_size; i += LINKAGE_DATA_ENTRY_SIZE) {
290 struct vector *symbol_name
291 = (struct vector *) PTR(data_vector->data[i]);
292 long type = fixnum_value(data_vector->data[i + 1]);
293 lispobj lib_list = data_vector->data[i + 2];
294 char c_symbol_name[1000];
296 convert_lisp_string(c_symbol_name, symbol_name->data, (symbol_name->length >> 2));
298 if (type == LINKAGE_DATA_TYPE && lib_list != NIL) {
299 void *target_addr = os_dlsym(c_symbol_name, lib_list);
302 lose("%s is not defined.\n", c_symbol_name);
304 arch_make_linkage_entry(i / LINKAGE_DATA_ENTRY_SIZE, target_addr,
308 #endif /* LINKAGE_TABLE */
311 /* Make entry for the symbol at entry in LINKAGE_TABLE_DATA. Called
312 from register-foreign-linkage. */
314 extern void undefined_foreign_symbol_trap(lispobj arg);
318 os_link_one_symbol(long entry)
321 lispobj linkage_data_obj = SymbolValue(LINKAGE_TABLE_DATA);
322 struct array *linkage_data = 0;
324 struct vector *data_vector = 0;
325 struct vector *symbol_name;
328 long table_index = entry * LINKAGE_DATA_ENTRY_SIZE;
329 char c_symbol_name[1000];
331 linkage_data = (struct array *) PTR(linkage_data_obj);
332 table_size = fixnum_value(linkage_data->fill_pointer);
333 if (table_index >= table_size - 1) {
336 data_vector = (struct vector *) PTR(linkage_data->data);
337 symbol_name = (struct vector *) PTR(data_vector->data[table_index]);
338 type = fixnum_value(data_vector->data[table_index + 1]);
340 convert_lisp_string(c_symbol_name, symbol_name->data, (symbol_name->length >> 2));
342 target_addr = os_dlsym(c_symbol_name,
343 data_vector->data[table_index + 2]);
345 fprintf(stderr, "Looked up %s symbol %s at %lx\n",
346 type == LINKAGE_CODE_TYPE ? "code" : "data",
347 c_symbol_name, (unsigned long) target_addr);
350 undefined_foreign_symbol_trap((lispobj) data_vector->data[table_index]);
352 arch_make_linkage_entry(entry, target_addr, type);
353 return (unsigned long) target_addr;
356 #endif /* LINKAGE_TABLE */
360 lazy_resolve_linkage(unsigned long retaddr)
363 unsigned long target_addr = os_link_one_symbol(arch_linkage_entry(retaddr));
368 #endif /* LINKAGE_TABLE */
375 /* The end of the control stack contains two guard zones:
377 +----------+ stack start (stack growing down)
385 +----------+ CONTROL_STACK_START
387 Both the yellow zone and the red zone are write-protected.
389 When entering the yellow zone, we unprotect the yellow zone and
390 make Lisp signal a control stack exhausted error, with stack
391 contents left intact for the debugger, which is entered.
393 When hitting the red zone we arrange for calling a function that
394 throws back to the top-level. */
396 #ifndef YELLOW_ZONE_SIZE
397 #define YELLOW_ZONE_SIZE 0x8000 /* 32K */
400 #ifndef RED_ZONE_SIZE
401 #define RED_ZONE_SIZE YELLOW_ZONE_SIZE
404 /* Return the start addresses of the yellow and red zones in
405 *YELLOW_START and *RED_START. */
408 guard_zones(char **yellow_start, char **red_start)
410 #if (defined(i386) || defined(__x86_64))
412 * All x86's have a control stack (aka C stack) that grows down.
414 char *end = (char *) CONTROL_STACK_START;
417 *yellow_start = *red_start + RED_ZONE_SIZE;
420 * On Solaris/sparc, the C stack grows down, but the Lisp control
421 * stack grows up. The stack zones begin just before the end of the
422 * control stack area.
425 char *end = (char *) CONTROL_STACK_START + control_stack_size;
427 *red_start = end - RED_ZONE_SIZE;
428 *yellow_start = *red_start - YELLOW_ZONE_SIZE;
432 /* Return the guard zone FAULT_ADDR is in or 0 if not in a guard
436 control_stack_zone(void *fault_addr)
438 char *yellow_start, *red_start;
439 char *p = (char *) fault_addr;
441 guard_zones(&yellow_start, &red_start);
443 if (p >= yellow_start && p < yellow_start + YELLOW_ZONE_SIZE)
445 else if (p >= red_start && p < red_start + RED_ZONE_SIZE)
451 /* Protect/unprotect the guard zone ZONE of the control stack. */
454 os_guard_control_stack(int zone, int guard)
456 char *yellow_start, *red_start;
459 guard_zones(&yellow_start, &red_start);
462 flags = OS_VM_PROT_READ | OS_VM_PROT_EXECUTE;
464 flags = OS_VM_PROT_ALL;
466 if (zone == YELLOW_ZONE)
467 os_protect((os_vm_address_t) yellow_start, YELLOW_ZONE_SIZE, flags);
468 else if (zone == RED_ZONE)
469 os_protect((os_vm_address_t) red_start, RED_ZONE_SIZE, flags);
471 char *start = red_start < yellow_start ? red_start : yellow_start;
473 os_protect((os_vm_address_t) start, RED_ZONE_SIZE + YELLOW_ZONE_SIZE,
478 /* Handle a possible guard zone hit at FAULT_ADDR. Value is
479 non-zero if FAULT_ADDR is in a guard zone. */
482 os_control_stack_overflow(void *fault_addr, os_context_t * context)
484 enum stack_zone_t zone;
486 zone = control_stack_zone(fault_addr);
488 if (zone == YELLOW_ZONE || zone == RED_ZONE) {
492 fprintf(stderr, "hit end of control stack in zone %s\n",
493 (zone == YELLOW_ZONE) ? "YELLOW" : (zone ==
494 RED_ZONE) ? "RED" : "BOTH");
496 /* Unprotect the stack, giving us some room on the stack for
497 error handling in Lisp. Fake a stack frame for this
499 os_guard_control_stack(zone, 0);
501 build_fake_control_stack_frame(context);
503 /* The protection violation signal is delivered on a signal
504 stack different from the normal stack, so that we don't
505 trample on the guard pages of the normal stack while handling
506 the signal. To get a Lisp function called when the signal
507 handler returns, we change the return address of the signal
508 context to the address of the function we want to be
510 if (zone == RED_ZONE)
511 error = SymbolFunction(RED_ZONE_HIT);
513 error = SymbolFunction(YELLOW_ZONE_HIT);
515 #if defined(i386) || defined(__x86_64)
516 SC_PC(context) = (int) ((struct function *) PTR(error))->code;
517 SC_REG(context, reg_NARGS) = 0;
519 /* This part should be common to all non-x86 ports */
520 SC_PC(context) = (long) ((struct function *) PTR(error))->code;
521 SC_NPC(context) = SC_PC(context) + 4;
522 SC_REG(context, reg_NARGS) = 0;
523 SC_REG(context, reg_LIP) =
524 (long) ((struct function *) PTR(error))->code;
525 SC_REG(context, reg_CFP) = (long) current_control_frame_pointer;
526 /* This is sparc specific */
527 SC_REG(context, reg_CODE) = ((long) PTR(error)) + type_FunctionPointer;
529 #error os_control_stack_overflow not implemented for this system
537 #else /* not RED_ZONE_HIT */
539 /* Dummy for bootstrapping. */
542 os_guard_control_stack(int zone, int guard)
546 #endif /* not RED_ZONE_HIT */