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);

}

(2)mach_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

);

(4)mach 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;

}

(5)mach_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_descriptor;routine_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的实现哦!

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

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

时间: 2024-07-28 20:36:46

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

Mac内核XNU的Mach子系统的一个完整过程的代码跟踪

一个完整的mach子系统 mach子系统包括了很多内核功能的实现,比如VM子系统(内存管理).host子系统(主机硬件信息的处理).thread子系统(thread相关实现).exc子系统(异常处理相关):现在拿thread_act为例来跟踪一下代码,希望能够简单地了解vm子系统的概况. (1)thread_act子系统的实现分为两部分: thread_actServer.c和thread_actUser.c,分别实现了内核中mach msg消息接收和发送的各个API. 基本逻辑是:调用thre

perf 对两个map是否重叠的判断,以及函数map_groups__fixup_overlappings代码逻辑

该标题可以抽象出来的问题是:两个前开后闭的区间 rangeA 和 rangeB,如何判断这两个区间是否重叠.这个问题在内核中非常重要,虚拟地址空间的划分需要它,perf中map_group的构建也需要它,下面直接给出该问题的解决思路: 找出不重叠的情况,其他的情况都是重叠的,perf中mmap__overlay函数是这样解决的: int map__overlap(struct map *l, struct map *r) {    if (l->start > r->start) { /

(笔记)Linux内核中内存相关的操作函数

linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) 内核空间申请指定大小的内存区域,返回内核空间虚拟地址.在函数实现中,如果申请的内存空间较大的话,会从buddy系统申请若干内存页面,如果申请的内存空间大小较小的话,会从slab系统中申请内存空间.有关buddy和slab,请参见<linux内核之内存管理.doc> gfp_t flags 的选项

第3阶段——内核启动分析之start_kernel初始化函数(5)

内核启动分析之start_kernel初始化函数(init/main.c) stext函数启动内核后,就开始进入start_kernel初始化各个函数, 下面只是浅尝辄止的描述一下函数的功能,很多函数真正理解需要对linux相关体系有很深的了解后才能明白 代码如下: asmlinkage void __init start_kernel(void) { char * command_line; extern struct kernel_param __start___param[], __sto

线程同步——内核对象实现线程同步——等待函数

1 对于内核对象实现线程同步,不得不提三点: 2 1)大多数内核对象既有触发也有未触发两个状态 3 比如:进程.线程.作业.文件流.事件.可等待的计时器.信号量.互斥量 4 2)等待函数:等待函数使线程自愿进入等待状态,直到指定的内核对象变为触发状态为止, 5 说道等待我们最喜欢不过了,因为这样不会浪费我们宝贵的CPU时间. 6 3)对于自动重置对象来说,当对象被触发时,函数会自动检测到(手动重置对象为触发是,函数也能检测到), 7 并开始执行,但是在函数会在返回之前使事件变为非触发状态. 8

linux内核中的排序接口--sort函数

linux内核中的sort函数,事实上跟我们所说的qsort函数非常像,我们来看看qsort: qsort 的函数原型是 void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*)); 參数:  1 .待排序数组首地址 2 .数组中待排序元素数量 3 .各元素的占用空间大小 4 .指向函数的指针.用于确定排序的顺序. 当中compare函数应写为: 1 2 3 4 int c

《linux 内核完全剖析》sched.c sched.h 代码分析笔记

sched.c sched.h 代码分析笔记 首先上header file sched.h #ifndef _SCHED_H #define _SCHED_H #define HZ 100 #define NR_TASKS 64 #define TASK_SIZE 0x04000000 #define LIBRARY_SIZE 0x00400000 #if (TASK_SIZE & 0x3fffff) #error "TASK_SIZE must be multiple of 4M&qu

在vs.net 2010,2015 等版本,给JS函数添加代码提示\注释

经常编写JS的朋友常常会因为函数写多了,隔一段时间就会忘记了函数的用途,或者函数里带的参数作用情况,这个时候会联想到VS工具里的强大提示功能,多希望也能在JS上实现呀,告诉你,这个想法并不是多难,VS2010以经帮我们解决了这个问题,下面看下具体是怎么操作的: 1 <script> 2 function SayHi(name, age) { 3 /// <summary>自我介绍名字和年龄的函数</summary> 4 /// <param name="

php分页函数示例代码,php分页代码实现方法

php分页函数示例代码 分享一例php分页函数代码,用此函数实现分页代码很不错. 代码,php分页函数. <?php /* * Created on 2011-07-28 * Author : LKK , http://lianq.net * 使用方法: require_once('mypage.php'); $result=mysql_query("select * from mytable", $myconn); $total=mysql_num_rows($result);