···2525 servers/thread_act.o \
2626 mig/duct.o proc_entry.o bsd_ioctl.o \
2727 psynch/psynch_mutex.o psynch/pthread_kill.o \
2828- psynch/psynch_cv.o
2828+ psynch/psynch_cv.o primitives/timer.o
29293030# Otherwise we were called directly from the command
3131# line; invoke the kernel build system.
+31-3
src/lkm/api.h
···11/*
22 * Darling Mach Linux Kernel Module
33- * Copyright (C) 2015 Lubos Dolezel
33+ * Copyright (C) 2015-2017 Lubos Dolezel
44 *
55 * This program is free software; you can redistribute it and/or
66 * modify it under the terms of the GNU General Public License
···2121#define LKM_API_H
2222#include <stdint.h>
23232424-#define DARLING_MACH_API_VERSION 1
2525-#define DARLING_MACH_API_VERSION_STR "1"
2424+#define darling_mach_xstr(a) darling_mach_str(a)
2525+#define darling_mach_str(a) #a
2626+2727+#define DARLING_MACH_API_VERSION 2
2828+#define DARLING_MACH_API_VERSION_STR darling_mach_xstr(DARLING_MACH_API_VERSION)
26292730#define DARLING_MACH_API_BASE 0x1000
2831···5255 NR_psynch_cvwait_trap, // 0x15
5356 NR_psynch_cvsignal_trap,
5457 NR_psynch_cvbroad_trap,
5858+ NR_mk_timer_create_trap,
5959+ NR_mk_timer_arm_trap,
6060+ NR_mk_timer_cancel_trap,
6161+ NR_mk_timer_destroy_trap,
5562};
56635764struct mach_port_mod_refs_args
···214221 uint32_t ugen;
215222 uint64_t tid;
216223 uint32_t flags;
224224+};
225225+226226+struct mk_timer_arm_args
227227+{
228228+ unsigned int timer_port;
229229+ /* This is mach_absolute_time() based time */
230230+ uint64_t expire_time;
231231+};
232232+233233+struct mk_timer_cancel_args
234234+{
235235+ unsigned int timer_port;
236236+ uint64_t* result_time;
237237+#ifdef __i386__
238238+ uint32_t pad1;
239239+#endif
240240+};
241241+242242+struct mk_timer_destroy_args
243243+{
244244+ unsigned int timer_port;
217245};
218246219247#pragma pack (pop)
+11-7
src/lkm/ipc_msg.c
···433433 debug_msg("ipc_msg_deliver()\n");
434434435435 // MIG call handling
436436- if (kmsg->target->port->is_server_port)
436436+ if (kmsg->target->port->is_server_port && kmsg->target->port->server_port.subsystem != NULL)
437437 {
438438 debug_msg("--> invoke_server\n");
439439 return ipc_msg_invoke_server(kmsg, timeout, options);
···453453 list_add(&delivery->list, &port->messages);
454454 port->queue_size++;
455455456456+ debug_msg("-> msg enqueued (%d b), waking up queue %p, queue size %d\n", kmsg->msg->msgh_size, &port->queue_recv, port->queue_size);
457457+456458 // Wake up waiting receivers
457457- wake_up_interruptible(&port->queue_recv);
459459+ wake_up(&port->queue_recv);
458460459461 // Wait (unless target is send once)
460462 if (kmsg->target->type != MACH_PORT_RIGHT_SEND_ONCE)
···525527 }
526528 else
527529 {
530530+ debug_msg("msg delivered\n");
528531 darling_mach_port_t* port;
529532530533 ipc_right_lock_port(kmsg->target);
···904907 ipc_port_unlock(right->port);
905908 locked = false;
906909907907- debug_msg("\t-> going to wait with timeout %d\n", timeout);
910910+ debug_msg("\t-> going to wait with timeout %d on queue %p (intr: %d)\n", timeout, &right->port->queue_recv, options & MACH_RCV_INTERRUPT);
908911909909-910912 // wait for ipc_msg_deliver() to be called somewhere
911913 if (timeout)
912914 {
···927929 {
928930 if (options & MACH_RCV_INTERRUPT)
929931 {
930930- err = wait_event_interruptible(right->port->queue_send,
932932+ err = wait_event_interruptible(right->port->queue_recv,
931933 (right->port->queue_size != 0 || !PORT_IS_VALID(right->port)));
932934 }
933935 else
934936 {
935935- err = wait_event_killable(right->port->queue_send,
937937+ err = wait_event_killable(right->port->queue_recv,
936938 (right->port->queue_size != 0 || !PORT_IS_VALID(right->port)));
937939 if (err == 0)
938940 err = 1;
939941 }
940942 }
943943+944944+ debug_msg("\t-> woken up from waiting, queue size: %d\n", right->port->queue_size);
941945942946 if (err == -ERESTARTSYS)
943947 {
···10451049 {
10461050 // Mark the message as delivered and wake up the sender.
10471051 delivery->delivered = true;
10481048- wake_up_interruptible(&right->port->queue_send);
10521052+ wake_up(&right->port->queue_send);
10491053 }
1050105410511055 break;
+1-1
src/lkm/ipc_port.c
···9595 if (port->server_port.cb_free != NULL)
9696 port->server_port.cb_free(&port->server_port);
9797 }
9898- else if (port->is_port_set)
9898+ if (port->is_port_set)
9999 {
100100 // Iterate referenced ports
101101 list_for_each(p, &port->members)
+3-3
src/lkm/ipc_port.h
···5050 /* Whether this port is associated with a Mach server */
5151 bool is_server_port : 1;
5252 bool is_port_set : 1;
5353+5454+ /* If is_server_port is true */
5555+ server_port_t server_port;
53565457 union
5558 {
5656- /* If is_server_port is true */
5757- server_port_t server_port;
5858-5959 /* Members for message exchange */
6060 struct
6161 {
+1
src/lkm/ipc_server.h
···2424#include "traps.h"
25252626#define PORT_TYPE_SEMAPHORE 1
2727+#define PORT_TYPE_TIMER 2
27282829/*
2930 * The following functions associate a port with the named kernel server.
+219
src/lkm/primitives/timer.c
···11+/*
22+ * Darling Mach Linux Kernel Module
33+ * Copyright (C) 2017 Lubos Dolezel
44+ *
55+ * This program is free software; you can redistribute it and/or
66+ * modify it under the terms of the GNU General Public License
77+ * as published by the Free Software Foundation; either version 2
88+ * of the License, or (at your option) any later version.
99+ *
1010+ * This program is distributed in the hope that it will be useful,
1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313+ * GNU General Public License for more details.
1414+ *
1515+ * You should have received a copy of the GNU General Public License
1616+ * along with this program; if not, write to the Free Software
1717+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1818+ */
1919+2020+#include <mach/mk_timer.h>
2121+#include "../mach_includes.h"
2222+#include "timer.h"
2323+#include "../ipc_server.h"
2424+#include "../ipc_port.h"
2525+#include "../ipc_right.h"
2626+#include "../debug.h"
2727+#include <linux/timer.h>
2828+#include <linux/jiffies.h>
2929+#include <linux/workqueue.h>
3030+#include <linux/delay.h>
3131+3232+struct mach_timer
3333+{
3434+ darling_mach_port_t* port;
3535+3636+ bool armed;
3737+ uint64_t expire_time, arm_time;
3838+3939+ struct timer_list timer;
4040+4141+ struct work_struct work;
4242+};
4343+4444+static struct workqueue_struct* _mach_timer_wq;
4545+4646+static void
4747+mach_timer_destroy(server_port_t* port);
4848+4949+static void
5050+mach_timer_expired(unsigned long data);
5151+5252+static void
5353+mach_timer_expired_worker(struct work_struct* work);
5454+5555+void
5656+mach_timer_setup(darling_mach_port_t* port)
5757+{
5858+ struct mach_timer* mt;
5959+6060+ port->is_server_port = true;
6161+ port->server_port.port_type = PORT_TYPE_TIMER;
6262+ port->server_port.subsystem = NULL;
6363+ port->server_port.cb_free = mach_timer_destroy;
6464+6565+ mt = (struct mach_timer*) kmalloc(sizeof(struct mach_timer),
6666+ GFP_KERNEL);
6767+ port->server_port.private_data = mt;
6868+6969+ mt->port = port;
7070+ mt->armed = false;
7171+7272+ setup_timer(&mt->timer, mach_timer_expired, (unsigned long) mt);
7373+ INIT_WORK(&mt->work, mach_timer_expired_worker);
7474+}
7575+7676+// Arm the timer. Change the expire time if it is already armed.
7777+kern_return_t
7878+mach_timer_arm(darling_mach_port_t* port, uint64_t expire_time)
7979+{
8080+ struct mach_timer* mt = (struct mach_timer*) port->server_port.private_data;
8181+ struct timespec now;
8282+ int64_t diffns;
8383+8484+ ktime_get_ts(&now);
8585+8686+ mt->arm_time = now.tv_nsec + now.tv_sec * NSEC_PER_SEC;
8787+ mt->expire_time = expire_time;
8888+ mt->armed = true;
8989+9090+ diffns = expire_time - mt->arm_time;
9191+9292+ mod_timer(&mt->timer, jiffies + nsecs_to_jiffies(diffns));
9393+9494+ return KERN_SUCCESS;
9595+}
9696+9797+// Disarm the timer. Do nothing if it isn't armed.
9898+kern_return_t
9999+mach_timer_cancel(darling_mach_port_t* port, uint64_t* expire_time)
100100+{
101101+ struct mach_timer* mt = (struct mach_timer*) port->server_port.private_data;
102102+103103+ if (mt->armed)
104104+ {
105105+ *expire_time = mt->expire_time;
106106+107107+ mt->armed = false;
108108+ while (!del_timer(&mt->timer))
109109+ usleep_range(1000, 20000);
110110+ }
111111+ else
112112+ *expire_time = 0;
113113+114114+ return KERN_SUCCESS;
115115+}
116116+117117+void
118118+mach_timer_destroy(server_port_t* port)
119119+{
120120+ struct mach_timer* mt;
121121+122122+ mt = (struct mach_timer*) port->private_data;
123123+124124+ if (mt->armed)
125125+ {
126126+ mt->armed = false;
127127+ while (!del_timer(&mt->timer))
128128+ usleep_range(1000, 20000);
129129+130130+ // Ensure this timer hasn't just recently fired,
131131+ // because we are about to be destroyed.
132132+ flush_workqueue(_mach_timer_wq);
133133+ }
134134+}
135135+136136+// Executed in a workqueue
137137+static void
138138+mach_timer_expired_worker(struct work_struct* work)
139139+{
140140+ struct mach_timer* mt;
141141+ mk_timer_expire_msg_t* msg;
142142+ struct ipc_kmsg* kmsg;
143143+ darling_mach_port_right_t* send_once;
144144+ kern_return_t rv;
145145+146146+ msg = (mk_timer_expire_msg_t*) kzalloc(sizeof(mk_timer_expire_msg_t),
147147+ GFP_KERNEL);
148148+149149+ mt = container_of(work, struct mach_timer, work);
150150+151151+#if 0 // It seems XNU no longer fills these out
152152+ struct timespec now;
153153+154154+ msg->unused[0] = mt->arm_time;
155155+ msg->unused[1] = mt->expire_time;
156156+157157+ ktime_get_ts(&now);
158158+159159+ msg->unused[2] = now.tv_nsec + now.tv_sec * NSEC_PER_SEC;
160160+#endif
161161+162162+ msg->header.msgh_size = sizeof(*msg);
163163+ msg->header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0, 0, 0);
164164+165165+ // Create a temporary send once right and call ipc_msg_deliver().
166166+ ipc_port_lock(mt->port);
167167+ send_once = ipc_right_new(mt->port, MACH_PORT_RIGHT_SEND_ONCE);
168168+169169+ // Allocate a kernel message wrapper
170170+ kmsg = (struct ipc_kmsg*) kmalloc(sizeof(struct ipc_kmsg), GFP_KERNEL);
171171+172172+ kmsg->msg = (mach_msg_header_t*) msg;
173173+ kmsg->target = send_once;
174174+ kmsg->reply = NULL;
175175+ kmsg->complex_items = NULL;
176176+177177+ // We specify no timeout, but messages sent to send once rights
178178+ // are delivered asynchronously.
179179+ rv = ipc_msg_deliver(kmsg, MACH_MSG_TIMEOUT_NONE, 0);
180180+181181+ kfree(kmsg);
182182+183183+ if (rv != KERN_SUCCESS)
184184+ {
185185+ debug_msg("Timer notification delivery failed: %d\n", rv);
186186+187187+ kfree(msg);
188188+ // ipc_right_put(send_once);
189189+ ipc_port_unlock(mt->port);
190190+ }
191191+ else
192192+ debug_msg("Timer notification posted\n");
193193+}
194194+195195+// Executed in atomic context
196196+static void
197197+mach_timer_expired(unsigned long data)
198198+{
199199+ struct mach_timer* mt = (struct mach_timer*) data;
200200+201201+ if (mt->armed)
202202+ {
203203+ mt->armed = false;
204204+ queue_work(_mach_timer_wq, &mt->work);
205205+ }
206206+}
207207+208208+void
209209+mach_timer_init(void)
210210+{
211211+ _mach_timer_wq = create_singlethread_workqueue("mach_timer");
212212+}
213213+214214+void
215215+mach_timer_exit(void)
216216+{
217217+ destroy_workqueue(_mach_timer_wq);
218218+}
219219+
+40
src/lkm/primitives/timer.h
···11+/*
22+ * Darling Mach Linux Kernel Module
33+ * Copyright (C) 2017 Lubos Dolezel
44+ *
55+ * This program is free software; you can redistribute it and/or
66+ * modify it under the terms of the GNU General Public License
77+ * as published by the Free Software Foundation; either version 2
88+ * of the License, or (at your option) any later version.
99+ *
1010+ * This program is distributed in the hope that it will be useful,
1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313+ * GNU General Public License for more details.
1414+ *
1515+ * You should have received a copy of the GNU General Public License
1616+ * along with this program; if not, write to the Free Software
1717+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1818+ */
1919+2020+#ifndef _PRIMITIVES_TIMER_H
2121+#define _PRIMITIVES_TIMER_H
2222+#include "../ipc_types.h"
2323+2424+void
2525+mach_timer_init(void);
2626+2727+void
2828+mach_timer_exit(void);
2929+3030+void
3131+mach_timer_setup(darling_mach_port_t* port);
3232+3333+kern_return_t
3434+mach_timer_arm(darling_mach_port_t* port, uint64_t expire_time);
3535+3636+kern_return_t
3737+mach_timer_cancel(darling_mach_port_t* port, uint64_t* expire_time);
3838+3939+#endif
4040+