码迷,mamicode.com
首页 > 系统相关 > 详细

Mac内核XNU的mach_vm子系统某个函数的代码逻辑

时间:2015-08-13 18:19:28      阅读:1194      评论:0      收藏:0      [点我收藏+]

标签:

Mac内核XNU的mach_vm子系统某个函数的代码逻辑


mach子系统包括了很多内核功能的实现,比如VM子系统(内存管理)、host子系统(主机硬件信息的处理)、thread子系统(thread相关实现)、exc子系统(异常处理相关)下面跟踪一下mach_vm子系统的mach_vm_allocate函数

 

 

1)最顶层函数mach_vm_allocate

 

它的实现,调用了两个函数(要么这个,要么另一个):

 

------ xnu/libsyscall/mach/mach_vm.c ------

 

kern_return_t mach_vm_allocate(

         mach_port_name_t target,

         mach_vm_address_t *address,

         mach_vm_size_t size,

         int flags)

{

         kern_return_t rv;

 

         rv = _kernelrpc_mach_vm_allocate_trap(target, address, size, flags);

 

         if (rv == MACH_SEND_INVALID_DEST)

                  rv = _kernelrpc_mach_vm_allocate(target, address, size, flags);

 

         if (__syscall_logger) {

                  int userTagFlags = flags & VM_FLAGS_ALIAS_MASK;

                  __syscall_logger(stack_logging_type_vm_allocate | userTagFlags, (uintptr_t)target, (uintptr_t)size, 0, (uintptr_t)*address, 0);

         }

 

         return (rv);

}

 

 

 

1.0看第一个函数的实现

 

函数_kernelrpc_mach_vm_allocate的实现在哪里呢?检索了xnu/osfmk/下面的代码,只有一个:

 

------ xnu/osfmk/ipc/mach_vm_kernelrpc.c ------

 

int _kernelrpc_mach_vm_allocate_trap(struct _kernelrpc_mach_vm_allocate_trap_args *args)

{

         mach_vm_offset_t addr;

         task_t task = port_name_to_task(args->target);

         int rv = MACH_SEND_INVALID_DEST;

 

         if (task != current_task())

                  goto done;

 

         if (copyin(args->addr, (char *)&addr, sizeof (addr)))

                  goto done;

 

         rv = mach_vm_allocate(task->map, &addr, args->size, args->flags);

         if (rv == KERN_SUCCESS)

                  rv = copyout(&addr, args->addr, sizeof (addr));

        

done:

         if (task)

                  task_deallocate(task);

         return (rv);

}

 

 

其中调用的函数mach_vm_allocate也有实现如下,可以函数调用到了最终的那个:

 

------ xnu/osfmk/vm/vm_user.c ------

 

/*

 *      mach_vm_allocate allocates "zero fill" memory in the specfied

 *      map.

 */

kern_return_t mach_vm_allocate(

         vm_map_t         map,

         mach_vm_offset_t     *addr,

         mach_vm_size_t        size,

         int                       flags)

{

         vm_map_offset_t map_addr;

         vm_map_size_t map_size;

         kern_return_t     result;

         boolean_t  anywhere;

 

         /* filter out any kernel-only flags */

         if (flags & ~VM_FLAGS_USER_ALLOCATE)

                  return KERN_INVALID_ARGUMENT;

 

         if (map == VM_MAP_NULL)

                  return(KERN_INVALID_ARGUMENT);

         if (size == 0) {

                  *addr = 0;

                  return(KERN_SUCCESS);

         }

 

         anywhere = ((VM_FLAGS_ANYWHERE & flags) != 0);

         if (anywhere) {

                  /*

                   * No specific address requested, so start candidate address

                   * search at the minimum address in the map.  However, if that

                   * minimum is 0, bump it up by PAGE_SIZE.  We want to limit

                   * allocations of PAGEZERO to explicit requests since its

                   * normal use is to catch dereferences of NULL and many

                   * applications also treat pointers with a value of 0 as

                   * special and suddenly having address 0 contain useable

                   * memory would tend to confuse those applications.

                   */

                  map_addr = vm_map_min(map);

                  if (map_addr == 0)

                          map_addr += VM_MAP_PAGE_SIZE(map);

         } else

                  map_addr = vm_map_trunc_page(*addr,

                                                 VM_MAP_PAGE_MASK(map));

         map_size = vm_map_round_page(size,

                                        VM_MAP_PAGE_MASK(map));

         if (map_size == 0) {

           return(KERN_INVALID_ARGUMENT);

         }

 

         result = vm_map_enter(

                          map,

                          &map_addr,

                          map_size,

                          (vm_map_offset_t)0,

                          flags,

                          VM_OBJECT_NULL,

                          (vm_object_offset_t)0,

                          FALSE,

                          VM_PROT_DEFAULT,

                          VM_PROT_ALL,

                          VM_INHERIT_DEFAULT);

 

         *addr = map_addr;

         return(result);

}

 

 

 

2mach_vm子系统的实现分为两部分

 

mach_vmServer.c和mach_vmUser.c,分别实现了内核中mach msg消息接收和发送的各个API。

 

基本逻辑是:调用mach_vmUser.c实现的API,接收到消息后mach_vmServer.c的对应函数被调用,真正完成一些事情。

 

说明一下,所有子系统的***Server.c***User.c代码都是通过MIG***.defs生成。

 

 

(3)mach_vm提供的头文件

 

头文件中申明了很多个mach_vm相关的函数,下面代码片段是_kernelrpc_mach_vm_allocate

 

------ xnu/osfmk/mach/mach_vm.h ------

 

/* Routine _kernelrpc_mach_vm_allocate */

#ifdef         mig_external

mig_external

#else

extern

#endif        /* mig_external */

kern_return_t _kernelrpc_mach_vm_allocate

(

         vm_map_t target,

         mach_vm_address_t *address,

         mach_vm_size_t size,

         int flags

);

 

 

4mach msg消息发送

 

下面是一个“类似系统调用”的函数(或者某个系统调用会间接调用这个函数),用于向mach_vm子系统发送mach msg消息请求某个服务(可以当作RPC)。

 

------ xnu/osfmk/mach/mach_vmUser.c ------

 

/* Routine _kernelrpc_mach_vm_allocate */

mig_external kern_return_t _kernelrpc_mach_vm_allocate

(

         vm_map_t target,

         mach_vm_address_t *address,

         mach_vm_size_t size,

         int flags

)

{

 

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

         typedef struct {

                  mach_msg_header_t Head;

                  NDR_record_t NDR;

                  mach_vm_address_t address;

                  mach_vm_size_t size;

                  int flags;

         } Request;

#ifdef  __MigPackStructs

#pragma pack()

#endif

 

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

         typedef struct {

                  mach_msg_header_t Head;

                  NDR_record_t NDR;

                  kern_return_t RetCode;

                  mach_vm_address_t address;

                  mach_msg_trailer_t trailer;

         } Reply;

#ifdef  __MigPackStructs

#pragma pack()

#endif

 

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

         typedef struct {

                  mach_msg_header_t Head;

                  NDR_record_t NDR;

                  kern_return_t RetCode;

                  mach_vm_address_t address;

         } __Reply;

#ifdef  __MigPackStructs

#pragma pack()

#endif

         /*

          * typedef struct {

          *     mach_msg_header_t Head;

          *     NDR_record_t NDR;

          *     kern_return_t RetCode;

          * } mig_reply_error_t;

          */

 

         union {

                  Request In;

                  Reply Out;

         } Mess;

 

         Request *InP = &Mess.In;

         Reply *Out0P = &Mess.Out;

 

         mach_msg_return_t msg_result;

 

#ifdef         __MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined

         kern_return_t check_result;

#endif        /* __MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined */

 

         __DeclareSendRpc(4800, "_kernelrpc_mach_vm_allocate")

 

         InP->NDR = NDR_record;

 

         InP->address = *address;

 

         InP->size = size;

 

         InP->flags = flags;

 

         InP->Head.msgh_bits =

                  MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);

         /* msgh_size passed as argument */

         InP->Head.msgh_request_port = target;

         InP->Head.msgh_reply_port = mig_get_reply_port();

         InP->Head.msgh_id = 4800;

 

         __BeforeSendRpc(4800, "_kernelrpc_mach_vm_allocate")

         msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);

         __AfterSendRpc(4800, "_kernelrpc_mach_vm_allocate")

         if (msg_result != MACH_MSG_SUCCESS) {

                  __MachMsgErrorWithoutTimeout(msg_result);

                  { return msg_result; }

         }

 

 

#if     defined(__MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined)

         check_result = __MIG_check__Reply___kernelrpc_mach_vm_allocate_t((__Reply___kernelrpc_mach_vm_allocate_t *)Out0P);

         if (check_result != MACH_MSG_SUCCESS)

                  { return check_result; }

#endif        /* defined(__MIG_check__Reply___kernelrpc_mach_vm_allocate_t__defined) */

 

         *address = Out0P->address;

 

         return KERN_SUCCESS;

}

 

 

5mach_vmServer.c中的mach msg消息接收

 

------ xnu/osfmk/mach/mach_vmServer.c ------

 

/* Description of this subsystem, for use in direct RPC */

const struct mach_vm_subsystem {

         mig_server_routine_t         server;      /* Server routine */

         mach_msg_id_t start; /* Min routine number */

         mach_msg_id_t end;  /* Max routine number + 1 */

         unsigned int       maxsize;   /* Max msg size */

         vm_address_t   reserved;  /* Reserved */

         struct routine_descriptor    /*Array of routine descriptors */

                  routine[20];

} mach_vm_subsystem = {

         mach_vm_server_routine,

         4800,

         4820,

         (mach_msg_size_t)sizeof(union __ReplyUnion__mach_vm_subsystem),

         (vm_address_t)0,

         {

          { (mig_impl_routine_t) 0,

          (mig_stub_routine_t) _X_kernelrpc_mach_vm_allocate, 5, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply___kernelrpc_mach_vm_allocate_t)},

          { (mig_impl_routine_t) 0,

          (mig_stub_routine_t) _X_kernelrpc_mach_vm_deallocate, 5, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply___kernelrpc_mach_vm_deallocate_t)},

          { (mig_impl_routine_t) 0,

          (mig_stub_routine_t) _X_kernelrpc_mach_vm_protect, 7, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply___kernelrpc_mach_vm_protect_t)},

          { (mig_impl_routine_t) 0,

          (mig_stub_routine_t) _Xmach_vm_inherit, 6, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_vm_inherit_t)},

          { (mig_impl_routine_t) 0,

          (mig_stub_routine_t) _X_kernelrpc_ma

 

 

解释一下上面的代码,声明并且实现了数据结构mach_vm_subsystem其中第6个成员是一个数组数组的元素是一个结构 ---routine_descriptorroutine_descriptor声明如下

 

------ xnu/osfmk/mach/mig.h ------

struct routine_descriptor {

         mig_impl_routine_t     impl_routine;      /* Server work func pointer   */

         mig_stub_routine_t    stub_routine;     /* Unmarshalling func pointer */

         unsigned int                argc;                  /* Number of argument words   */

         unsigned int                descr_count;     /* Number complex descriptors */

         routine_arg_descriptor_t

                                                     arg_descr;                  /* pointer to descriptor array*/

         unsigned int                max_reply_msg;        /* Max size for reply msg     */

};

typedef struct routine_descriptor *routine_descriptor_t;

 

typedef struct routine_descriptor mig_routine_descriptor;

typedef mig_routine_descriptor *mig_routine_descriptor_t;

 

 

6跟踪mach_vm_subsystem_X_kernelrpc_mach_vm_allocate的实现

 

------ xnu/osfmk/mach/mach_vmServer.c ------

 

/* Routine _kernelrpc_mach_vm_allocate */

mig_internal novalue _X_kernelrpc_mach_vm_allocate

         (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)

{

 

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

         typedef struct {

                  mach_msg_header_t Head;

                  NDR_record_t NDR;

                  mach_vm_address_t address;

                  mach_vm_size_t size;

                  int flags;

                  mach_msg_trailer_t trailer;

         } Request;

#ifdef  __MigPackStructs

#pragma pack()

#endif

         typedef __Request___kernelrpc_mach_vm_allocate_t __Request;

         typedef __Reply___kernelrpc_mach_vm_allocate_t Reply;

 

         /*

          * typedef struct {

          *     mach_msg_header_t Head;

          *     NDR_record_t NDR;

          *     kern_return_t RetCode;

          * } mig_reply_error_t;

          */

 

         Request *In0P = (Request *) InHeadP;

         Reply *OutP = (Reply *) OutHeadP;

#ifdef         __MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined

         kern_return_t check_result;

#endif        /* __MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined */

 

         __DeclareRcvRpc(4800, "_kernelrpc_mach_vm_allocate")

         __BeforeRcvRpc(4800, "_kernelrpc_mach_vm_allocate")

 

#if     defined(__MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined)

         check_result = __MIG_check__Request___kernelrpc_mach_vm_allocate_t((__Request *)In0P);

         if (check_result != MACH_MSG_SUCCESS)

                  { MIG_RETURN_ERROR(OutP, check_result); }

#endif        /* defined(__MIG_check__Request___kernelrpc_mach_vm_allocate_t__defined) */

 

         OutP->RetCode = _kernelrpc_mach_vm_allocate(In0P->Head.msgh_request_port, &In0P->address, In0P->size, In0P->flags);

         if (OutP->RetCode != KERN_SUCCESS) {

                  MIG_RETURN_ERROR(OutP, OutP->RetCode);

         }

 

         OutP->NDR = NDR_record;

 

 

         OutP->address = In0P->address;

 

         OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply));

         __AfterRcvRpc(4800, "_kernelrpc_mach_vm_allocate")

}

 

 

7最终实现不见

 

找遍xnu项目代码,没有_kernelrpc_mach_vm_allocate的实现哦!

这里就是之前提到“死胡同”和“没下文”的地方!

 

说明:一个大工程,总有一些死代码,永远跑不到的地方,应该干掉却没有干掉,这个不影响系统功能




Mac内核XNU的mach_vm子系统某个函数的代码逻辑

标签:

原文地址:http://my.oschina.net/u/614221/blog/491980

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!