2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (C) 1988, 1989, NeXT, Inc.
28 * File: kern/mach_loader.c
29 * Author: Avadis Tevanian, Jr.
31 * Mach object file loader (kernel version, for now).
33 * 21-Jul-88 Avadis Tevanian, Jr. (avie) at NeXT
36 #include <sys/param.h>
37 #include <sys/vnode.h>
39 #include <sys/namei.h>
42 #include <sys/malloc.h>
43 #include <sys/mount.h>
44 #include <sys/fcntl.h>
47 #include <mach/mach_types.h>
49 #include <kern/mach_loader.h>
51 #include <mach-o/fat.h>
52 #include <mach-o/loader.h>
54 #include <kern/cpu_number.h>
56 #include <vm/vm_map.h>
57 #include <vm/vm_kern.h>
58 #include <vm/vm_pager.h>
59 #include <vm/vnode_pager.h>
60 #include <mach/vm_statistics.h>
62 #include <mach/shared_memory_server.h>
63 #include <vm/vm_shared_memory_server.h>
65 #include <machine/vmparam.h>
68 * Prototypes of static functions.
76 struct mach_header
*header
,
77 unsigned long file_offset
,
78 unsigned long macho_size
,
83 struct segment_command
*scp
,
85 unsigned long pager_offset
,
86 unsigned long macho_size
,
87 unsigned long end_of_file
,
92 struct thread_command
*tcp
,
97 struct thread_command
*tcp
,
104 unsigned long total_size
109 unsigned long total_size
,
110 vm_offset_t
*user_stack
,
116 unsigned long total_size
,
117 vm_offset_t
*entry_point
120 struct dylinker_command
*lcp
,
122 thread_act_t thr_act
,
124 load_result_t
*result
128 struct mach_header
*mach_header
,
129 unsigned long *file_offset
,
130 unsigned long *macho_size
,
137 struct mach_header
*header
,
138 unsigned long file_offset
,
139 unsigned long macho_size
,
140 load_result_t
*result
,
141 thread_act_t thr_act
,
148 load_result_t myresult
;
151 boolean_t create_map
= TRUE
;
153 if (new_map
!= VM_MAP_NULL
) {
158 old_map
= current_map();
160 pmap
= get_task_pmap(current_task());
161 pmap_reference(pmap
);
163 pmap
= pmap_create((vm_size_t
) 0);
165 map
= vm_map_create(pmap
,
166 get_map_min(old_map
),
167 get_map_max(old_map
),
168 TRUE
); /**** FIXME ****/
175 *result
= (load_result_t
) { 0 };
177 lret
= parse_machfile(vp
, map
, thr_act
, header
, file_offset
, macho_size
,
180 if (lret
!= LOAD_SUCCESS
) {
182 vm_map_deallocate(map
); /* will lose pmap reference too */
186 * Commit to new map. First make sure that the current
187 * users of the task get done with it, and that we clean
188 * up the old contents of IPC and memory. The task is
189 * guaranteed to be single threaded upon return (us).
191 * Swap the new map for the old at the task level and at
192 * our activation. The latter consumes our new map reference
193 * but each leaves us responsible for the old_map reference.
194 * That lets us get off the pmap associated with it, and
195 * then we can release it.
198 task_halt(current_task());
200 old_map
= swap_task_map(current_task(), map
);
201 vm_map_deallocate(old_map
);
203 old_map
= swap_act_map(current_act(), map
);
206 pmap_switch(pmap
); /* Make sure we are using the new pmap */
208 vm_map_deallocate(old_map
);
210 return(LOAD_SUCCESS
);
214 extern vm_offset_t system_shared_region
;
221 thread_act_t thr_act
,
222 struct mach_header
*header
,
223 unsigned long file_offset
,
224 unsigned long macho_size
,
226 load_result_t
*result
229 struct machine_slot
*ms
;
231 struct load_command
*lcp
, *next
;
232 struct dylinker_command
*dlp
= 0;
235 vm_offset_t addr
, kl_addr
;
236 vm_size_t size
,kl_size
;
239 struct proc
*p
= current_proc(); /* XXXX */
245 * Break infinite recursion
248 return(LOAD_FAILURE
);
250 task
= (task_t
)get_threadtask(thr_act
);
255 * Check to see if right machine type.
257 ms
= &machine_slot
[cpu_number()];
258 if ((header
->cputype
!= ms
->cpu_type
) ||
259 !check_cpu_subtype(header
->cpusubtype
))
260 return(LOAD_BADARCH
);
262 switch (header
->filetype
) {
268 return (LOAD_FAILURE
);
274 return (LOAD_FAILURE
);
279 return (LOAD_FAILURE
);
283 return (LOAD_FAILURE
);
287 * Get the pager for the file.
289 UBCINFOCHECK("parse_machfile", vp
);
290 pager
= (void *) ubc_getpager(vp
);
293 * Map portion that must be accessible directly into
296 if ((sizeof (struct mach_header
) + header
->sizeofcmds
) > macho_size
)
297 return(LOAD_BADMACHO
);
300 * Round size of Mach-O commands up to page boundry.
302 size
= round_page(sizeof (struct mach_header
) + header
->sizeofcmds
);
304 return(LOAD_BADMACHO
);
307 * Map the load commands into kernel memory.
311 kl_addr
= kalloc(size
);
314 return(LOAD_NOSPACE
);
316 if(error
= vn_rdwr(UIO_READ
, vp
, addr
, size
, file_offset
,
317 UIO_SYSSPACE
, 0, p
->p_ucred
, &resid
, p
)) {
319 kfree(kl_addr
, kl_size
);
322 /* ubc_map(vp); */ /* NOT HERE */
325 * Scan through the commands, processing each one as necessary.
327 for (pass
= 1; pass
<= 2; pass
++) {
328 offset
= sizeof(struct mach_header
);
329 ncmds
= header
->ncmds
;
332 * Get a pointer to the command.
334 lcp
= (struct load_command
*)(addr
+ offset
);
335 offset
+= lcp
->cmdsize
;
338 * Check for valid lcp pointer by checking
341 if (offset
> header
->sizeofcmds
342 + sizeof(struct mach_header
)) {
344 kfree(kl_addr
, kl_size
);
345 return(LOAD_BADMACHO
);
349 * Check for valid command.
356 (struct segment_command
*) lcp
,
359 (unsigned long)ubc_getsize(vp
),
366 ret
= load_thread((struct thread_command
*)lcp
, thr_act
,
372 ret
= load_unixthread(
373 (struct thread_command
*) lcp
, thr_act
,
376 case LC_LOAD_DYLINKER
:
379 if (depth
== 1 || dlp
== 0)
380 dlp
= (struct dylinker_command
*)lcp
;
385 ret
= KERN_SUCCESS
;/* ignore other stuff */
387 if (ret
!= LOAD_SUCCESS
)
390 if (ret
!= LOAD_SUCCESS
)
393 if (ret
== LOAD_SUCCESS
&& dlp
!= 0) {
395 shared_region_mapping_t shared_region
;
396 struct shared_region_task_mappings map_info
;
397 shared_region_mapping_t next
;
400 vm_get_shared_region(task
, &shared_region
);
401 map_info
.self
= (vm_offset_t
)shared_region
;
402 shared_region_mapping_info(shared_region
,
403 &(map_info
.text_region
),
404 &(map_info
.text_size
),
405 &(map_info
.data_region
),
406 &(map_info
.data_size
),
407 &(map_info
.region_mappings
),
408 &(map_info
.client_base
),
409 &(map_info
.alternate_base
),
410 &(map_info
.alternate_next
),
411 &(map_info
.flags
), &next
);
413 if((map_info
.self
!= (vm_offset_t
)system_shared_region
) &&
414 (map_info
.flags
& SHARED_REGION_SYSTEM
)) {
415 shared_region_mapping_ref(system_shared_region
);
416 vm_set_shared_region(task
, system_shared_region
);
417 shared_region_mapping_dealloc(
418 (shared_region_mapping_t
)map_info
.self
);
424 p
->p_flag
|= P_NOSHLIB
; /* no shlibs in use */
425 addr
= map_info
.client_base
;
426 vm_map(map
, &addr
, map_info
.text_size
, 0,
427 (VM_MEMORY_SHARED_PMAP
<< 24)
429 map_info
.text_region
, 0, FALSE
,
430 VM_PROT_READ
, VM_PROT_READ
, VM_INHERIT_SHARE
);
431 addr
= map_info
.client_base
+ map_info
.text_size
;
432 vm_map(map
, &addr
, map_info
.data_size
,
434 map_info
.data_region
, 0, TRUE
,
435 VM_PROT_READ
, VM_PROT_READ
, VM_INHERIT_SHARE
);
437 ret
= load_dylinker(dlp
, map
, thr_act
, depth
, result
);
441 kfree(kl_addr
, kl_size
);
443 if ((ret
== LOAD_SUCCESS
) && (depth
== 1) &&
444 (result
->thread_count
== 0))
446 if (ret
== LOAD_SUCCESS
)
455 struct segment_command
*scp
,
457 unsigned long pager_offset
,
458 unsigned long macho_size
,
459 unsigned long end_of_file
,
461 load_result_t
*result
465 vm_offset_t map_addr
, map_offset
;
466 vm_size_t map_size
, seg_size
, delta_size
;
471 extern int print_map_addr
;
475 * Make sure what we get from the file is really ours (as specified
478 if (scp
->fileoff
+ scp
->filesize
> macho_size
)
479 return (LOAD_BADMACHO
);
481 seg_size
= round_page(scp
->vmsize
);
483 return(KERN_SUCCESS
);
486 * Round sizes to page size.
488 map_size
= round_page(scp
->filesize
);
489 map_addr
= trunc_page(scp
->vmaddr
);
491 map_offset
= pager_offset
+ scp
->fileoff
;
494 initprot
= (scp
->initprot
) & VM_PROT_ALL
;
495 maxprot
= (scp
->maxprot
) & VM_PROT_ALL
;
497 * Map a copy of the file into the address space.
500 &map_addr
, map_size
, (vm_offset_t
)0, FALSE
,
501 pager
, map_offset
, TRUE
,
504 if (ret
!= KERN_SUCCESS
)
505 return(LOAD_NOSPACE
);
509 printf("LSegment: Mapped addr= %x; size = %x\n", map_addr
, map_size
);
512 * If the file didn't end on a page boundary,
513 * we need to zero the leftover.
515 delta_size
= map_size
- scp
->filesize
;
517 if (delta_size
> 0) {
520 ret
= vm_allocate(kernel_map
, &tmp
, delta_size
, TRUE
);
521 if (ret
!= KERN_SUCCESS
)
522 return(LOAD_RESOURCE
);
524 if (copyout(tmp
, map_addr
+ scp
->filesize
,
526 (void) vm_deallocate(
527 kernel_map
, tmp
, delta_size
);
528 return(LOAD_FAILURE
);
531 (void) vm_deallocate(kernel_map
, tmp
, delta_size
);
537 * If the virtual size of the segment is greater
538 * than the size from the file, we need to allocate
539 * zero fill memory for the rest.
541 delta_size
= seg_size
- map_size
;
542 if (delta_size
> 0) {
543 vm_offset_t tmp
= map_addr
+ map_size
;
545 ret
= vm_allocate(map
, &tmp
, delta_size
, FALSE
);
546 if (ret
!= KERN_SUCCESS
)
547 return(LOAD_NOSPACE
);
551 * Set protection values. (Note: ignore errors!)
554 if (scp
->maxprot
!= VM_PROT_DEFAULT
) {
555 (void) vm_protect(map
,
559 if (scp
->initprot
!= VM_PROT_DEFAULT
) {
560 (void) vm_protect(map
,
562 FALSE
, scp
->initprot
);
564 if ( (scp
->fileoff
== 0) && (scp
->filesize
!= 0) )
565 result
->mach_header
= map_addr
;
566 return(LOAD_SUCCESS
);
572 struct thread_command
*tcp
,
573 thread_act_t thr_act
,
574 load_result_t
*result
577 thread_t thread
= current_thread();
581 if (result
->thread_count
!= 0)
582 return (LOAD_FAILURE
);
584 thread
= getshuttle_thread(thr_act
);
585 ret
= load_threadstack(thread
,
586 (unsigned long *)(((vm_offset_t
)tcp
) +
587 sizeof(struct thread_command
)),
588 tcp
->cmdsize
- sizeof(struct thread_command
),
591 if (ret
!= LOAD_SUCCESS
)
595 result
->customstack
= 1;
597 result
->customstack
= 0;
598 ret
= load_threadentry(thread
,
599 (unsigned long *)(((vm_offset_t
)tcp
) +
600 sizeof(struct thread_command
)),
601 tcp
->cmdsize
- sizeof(struct thread_command
),
602 &result
->entry_point
);
603 if (ret
!= LOAD_SUCCESS
)
606 ret
= load_threadstate(thread
,
607 (unsigned long *)(((vm_offset_t
)tcp
) +
608 sizeof(struct thread_command
)),
609 tcp
->cmdsize
- sizeof(struct thread_command
));
610 if (ret
!= LOAD_SUCCESS
)
613 result
->unixproc
= TRUE
;
614 result
->thread_count
++;
616 return(LOAD_SUCCESS
);
622 struct thread_command
*tcp
,
623 thread_act_t thr_act
,
624 load_result_t
*result
633 task
= get_threadtask(thr_act
);
634 thread
= getshuttle_thread(thr_act
);
636 /* if count is 0; same as thr_act */
637 if (result
->thread_count
!= 0) {
638 kret
= thread_create(task
, &thread
);
639 if (kret
!= KERN_SUCCESS
)
640 return(LOAD_RESOURCE
);
641 thread_deallocate(thread
);
644 lret
= load_threadstate(thread
,
645 (unsigned long *)(((vm_offset_t
)tcp
) +
646 sizeof(struct thread_command
)),
647 tcp
->cmdsize
- sizeof(struct thread_command
));
648 if (lret
!= LOAD_SUCCESS
)
651 if (result
->thread_count
== 0) {
652 lret
= load_threadstack(thread
,
653 (unsigned long *)(((vm_offset_t
)tcp
) +
654 sizeof(struct thread_command
)),
655 tcp
->cmdsize
- sizeof(struct thread_command
),
659 result
->customstack
= 1;
661 result
->customstack
= 0;
663 if (lret
!= LOAD_SUCCESS
)
666 lret
= load_threadentry(thread
,
667 (unsigned long *)(((vm_offset_t
)tcp
) +
668 sizeof(struct thread_command
)),
669 tcp
->cmdsize
- sizeof(struct thread_command
),
670 &result
->entry_point
);
671 if (lret
!= LOAD_SUCCESS
)
675 * Resume thread now, note that this means that the thread
676 * commands should appear after all the load commands to
677 * be sure they don't reference anything not yet mapped.
680 thread_resume(thread
);
682 result
->thread_count
++;
684 return(LOAD_SUCCESS
);
692 unsigned long total_size
700 * Set the thread state.
703 while (total_size
> 0) {
706 total_size
-= (size
+2)*sizeof(unsigned long);
708 return(LOAD_BADMACHO
);
709 ret
= thread_setstatus(getact_thread(thread
), flavor
, ts
, size
);
710 if (ret
!= KERN_SUCCESS
)
711 return(LOAD_FAILURE
);
712 ts
+= size
; /* ts is a (unsigned long *) */
714 return(LOAD_SUCCESS
);
722 unsigned long total_size
,
723 vm_offset_t
*user_stack
,
731 while (total_size
> 0) {
734 total_size
-= (size
+2)*sizeof(unsigned long);
736 return(LOAD_BADMACHO
);
737 *user_stack
= USRSTACK
;
738 ret
= thread_userstack(thread
, flavor
, ts
, size
,
739 user_stack
, customstack
);
740 if (ret
!= KERN_SUCCESS
)
741 return(LOAD_FAILURE
);
742 ts
+= size
; /* ts is a (unsigned long *) */
744 return(LOAD_SUCCESS
);
752 unsigned long total_size
,
753 vm_offset_t
*entry_point
761 * Set the thread state.
764 while (total_size
> 0) {
767 total_size
-= (size
+2)*sizeof(unsigned long);
769 return(LOAD_BADMACHO
);
770 ret
= thread_entrypoint(thread
, flavor
, ts
, size
, entry_point
);
771 if (ret
!= KERN_SUCCESS
)
772 return(LOAD_FAILURE
);
773 ts
+= size
; /* ts is a (unsigned long *) */
775 return(LOAD_SUCCESS
);
782 struct dylinker_command
*lcp
,
784 thread_act_t thr_act
,
786 load_result_t
*result
792 struct mach_header header
;
793 unsigned long file_offset
;
794 unsigned long macho_size
;
796 load_result_t myresult
;
799 vm_offset_t dyl_start
, map_addr
;
800 vm_size_t dyl_length
;
802 name
= (char *)lcp
+ lcp
->name
.offset
;
804 * Check for a proper null terminated string.
808 if (p
>= (char *)lcp
+ lcp
->cmdsize
)
809 return(LOAD_BADMACHO
);
812 ret
= get_macho_vnode(name
, &header
, &file_offset
, &macho_size
, &vp
);
816 myresult
= (load_result_t
) { 0 };
822 copy_map
= vm_map_create(pmap_create(macho_size
),
823 get_map_min(map
), get_map_max( map
), TRUE
);
825 ret
= parse_machfile(vp
, copy_map
, thr_act
, &header
,
826 file_offset
, macho_size
,
832 if (get_map_nentries(copy_map
) > 0) {
834 dyl_start
= get_map_start(copy_map
);
835 dyl_length
= get_map_end(copy_map
) - dyl_start
;
837 map_addr
= dyl_start
;
838 ret
= vm_allocate(map
, &map_addr
, dyl_length
, FALSE
);
839 if (ret
!= KERN_SUCCESS
) {
840 ret
= vm_allocate(map
, &map_addr
, dyl_length
, TRUE
);
843 if (ret
!= KERN_SUCCESS
) {
848 ret
= vm_map_copyin(copy_map
, dyl_start
, dyl_length
, TRUE
,
850 if (ret
!= KERN_SUCCESS
) {
851 (void) vm_map_remove(map
,
853 map_addr
+ dyl_length
,
858 ret
= vm_map_copy_overwrite(map
, map_addr
, tmp
, FALSE
);
859 if (ret
!= KERN_SUCCESS
) {
860 vm_map_copy_discard(tmp
);
861 (void) vm_map_remove(map
,
863 map_addr
+ dyl_length
,
867 if (map_addr
!= dyl_start
)
868 myresult
.entry_point
+= (map_addr
- dyl_start
);
872 if (ret
== LOAD_SUCCESS
) {
873 result
->dynlinker
= TRUE
;
874 result
->entry_point
= myresult
.entry_point
;
878 vm_map_deallocate(copy_map
);
889 struct mach_header
*mach_header
,
890 unsigned long *file_offset
,
891 unsigned long *macho_size
,
896 struct vattr attr
, *atp
;
897 struct nameidata nid
, *ndp
;
898 struct proc
*p
= current_proc(); /* XXXX */
900 struct fat_arch fat_arch
;
901 int error
= KERN_SUCCESS
;
904 struct mach_header mach_header
;
905 struct fat_header fat_header
;
908 off_t fsize
= (off_t
)0;
909 struct ucred
*cred
= p
->p_ucred
;
914 /* init the namei data to point the file user's program name */
915 NDINIT(ndp
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
, path
, p
);
917 if (error
= namei(ndp
))
922 /* check for regular file */
923 if (vp
->v_type
!= VREG
) {
929 if (error
= VOP_GETATTR(vp
, &attr
, cred
, p
))
932 /* Check mount point */
933 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
) {
938 if ((vp
->v_mount
->mnt_flag
& MNT_NOSUID
) || (p
->p_flag
& P_TRACED
))
939 atp
->va_mode
&= ~(VSUID
| VSGID
);
941 /* check access. for root we have to see if any exec bit on */
942 if (error
= VOP_ACCESS(vp
, VEXEC
, cred
, p
))
944 if ((atp
->va_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) == 0) {
949 /* hold the vnode for the IO */
950 if (UBCINFOEXISTS(vp
) && !ubc_hold(vp
)) {
956 if (error
= VOP_OPEN(vp
, FREAD
, cred
, p
)) {
961 if(error
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)&header
, sizeof(header
), 0,
962 UIO_SYSSPACE
, IO_NODELOCKED
, cred
, &resid
, p
))
965 if (header
.mach_header
.magic
== MH_MAGIC
)
967 else if (header
.fat_header
.magic
== FAT_MAGIC
||
968 header
.fat_header
.magic
== FAT_CIGAM
)
971 error
= LOAD_BADMACHO
;
976 /* Look up our architecture in the fat file. */
977 error
= fatfile_getarch(vp
, (vm_offset_t
)(&header
.fat_header
), &fat_arch
);
978 if (error
!= LOAD_SUCCESS
)
981 /* Read the Mach-O header out of it */
982 error
= vn_rdwr(UIO_READ
, vp
, &header
.mach_header
,
983 sizeof(header
.mach_header
), fat_arch
.offset
,
984 UIO_SYSSPACE
, IO_NODELOCKED
, cred
, &resid
, p
);
986 error
= LOAD_FAILURE
;
990 /* Is this really a Mach-O? */
991 if (header
.mach_header
.magic
!= MH_MAGIC
) {
992 error
= LOAD_BADMACHO
;
996 *file_offset
= fat_arch
.offset
;
997 *macho_size
= fsize
= fat_arch
.size
;
1001 *macho_size
= fsize
= attr
.va_size
;
1004 *mach_header
= header
.mach_header
;
1007 ubc_setsize(vp
, fsize
); /* XXX why? */
1009 VOP_UNLOCK(vp
, 0, p
);
1014 VOP_UNLOCK(vp
, 0, p
);
1015 error
= VOP_CLOSE(vp
, FREAD
, cred
, p
);