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

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的实现哦!

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


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




转载于:https://my.oschina.net/u/614221/blog/491980

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值