dev_pager.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1993-1989 Carnegie Mellon University
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify and distribute this software and its
  7. * documentation is hereby granted, provided that both the copyright
  8. * notice and this permission notice appear in all copies of the
  9. * software, derivative works or modified versions, and any portions
  10. * thereof, and that both notices appear in supporting documentation.
  11. *
  12. * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13. * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14. * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15. *
  16. * Carnegie Mellon requests users of this software to return to
  17. *
  18. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  19. * School of Computer Science
  20. * Carnegie Mellon University
  21. * Pittsburgh PA 15213-3890
  22. *
  23. * any improvements or extensions that they make and grant Carnegie Mellon
  24. * the rights to redistribute these changes.
  25. */
  26. /*
  27. * Author: David B. Golub, Carnegie Mellon University
  28. * Date: 3/89
  29. *
  30. * Device pager.
  31. */
  32. #include <string.h>
  33. #include <mach/boolean.h>
  34. #include <mach/port.h>
  35. #include <mach/message.h>
  36. #include <mach/std_types.h>
  37. #include <mach/mach_types.h>
  38. #include <ipc/ipc_port.h>
  39. #include <ipc/ipc_space.h>
  40. #include <kern/debug.h>
  41. #include <kern/printf.h>
  42. #include <kern/queue.h>
  43. #include <kern/slab.h>
  44. #include <vm/vm_page.h>
  45. #include <vm/vm_kern.h>
  46. #include <vm/vm_user.h>
  47. #include <device/device_types.h>
  48. #include <device/ds_routines.h>
  49. #include <device/dev_hdr.h>
  50. #include <device/io_req.h>
  51. #include <device/memory_object_reply.user.h>
  52. #include <device/dev_pager.h>
  53. #include <device/blkio.h>
  54. /*
  55. * The device pager routines are called directly from the message
  56. * system (via mach_msg), and thus run in the kernel-internal
  57. * environment. All ports are in internal form (ipc_port_t),
  58. * and must be correctly reference-counted in order to be saved
  59. * in other data structures. Kernel routines may be called
  60. * directly. Kernel types are used for data objects (tasks,
  61. * memory objects, ports). The only IPC routines that may be
  62. * called are ones that masquerade as the kernel task (via
  63. * msg_send_from_kernel).
  64. *
  65. * Port rights and references are maintained as follows:
  66. * Memory object port:
  67. * The device_pager task has all rights.
  68. * Memory object control port:
  69. * The device_pager task has only send rights.
  70. * Memory object name port:
  71. * The device_pager task has only send rights.
  72. * The name port is not even recorded.
  73. * Regardless how the object is created, the control and name
  74. * ports are created by the kernel and passed through the memory
  75. * management interface.
  76. *
  77. * The device_pager assumes that access to its memory objects
  78. * will not be propagated to more that one host, and therefore
  79. * provides no consistency guarantees beyond those made by the
  80. * kernel.
  81. *
  82. * In the event that more than one host attempts to use a device
  83. * memory object, the device_pager will only record the last set
  84. * of port names. [This can happen with only one host if a new
  85. * mapping is being established while termination of all previous
  86. * mappings is taking place.] Currently, the device_pager assumes
  87. * that its clients adhere to the initialization and termination
  88. * protocols in the memory management interface; otherwise, port
  89. * rights or out-of-line memory from erroneous messages may be
  90. * allowed to accumulate.
  91. *
  92. * [The phrase "currently" has been used above to denote aspects of
  93. * the implementation that could be altered without changing the rest
  94. * of the basic documentation.]
  95. */
  96. /*
  97. * Basic device pager structure.
  98. */
  99. struct dev_pager {
  100. decl_simple_lock_data(, lock) /* lock for reference count */
  101. int ref_count; /* reference count */
  102. int client_count; /* How many memory_object_create
  103. * calls have we received */
  104. ipc_port_t pager; /* pager port */
  105. ipc_port_t pager_request; /* Known request port */
  106. ipc_port_t pager_name; /* Known name port */
  107. mach_device_t device; /* Device handle */
  108. int type; /* to distinguish */
  109. #define DEV_PAGER_TYPE 0
  110. #define CHAR_PAGER_TYPE 1
  111. /* char pager specifics */
  112. int prot;
  113. vm_size_t size;
  114. };
  115. typedef struct dev_pager *dev_pager_t;
  116. #define DEV_PAGER_NULL ((dev_pager_t)0)
  117. struct kmem_cache dev_pager_cache;
  118. void dev_pager_reference(dev_pager_t ds)
  119. {
  120. simple_lock(&ds->lock);
  121. ds->ref_count++;
  122. simple_unlock(&ds->lock);
  123. }
  124. void dev_pager_deallocate(dev_pager_t ds)
  125. {
  126. simple_lock(&ds->lock);
  127. if (--ds->ref_count > 0) {
  128. simple_unlock(&ds->lock);
  129. return;
  130. }
  131. simple_unlock(&ds->lock);
  132. kmem_cache_free(&dev_pager_cache, (vm_offset_t)ds);
  133. }
  134. /*
  135. * A hash table of ports for device_pager backed objects.
  136. */
  137. #define DEV_PAGER_HASH_COUNT 127
  138. struct dev_pager_entry {
  139. queue_chain_t links;
  140. ipc_port_t name;
  141. dev_pager_t pager_rec;
  142. };
  143. typedef struct dev_pager_entry *dev_pager_entry_t;
  144. queue_head_t dev_pager_hashtable[DEV_PAGER_HASH_COUNT];
  145. struct kmem_cache dev_pager_hash_cache;
  146. decl_simple_lock_data(,
  147. dev_pager_hash_lock)
  148. #define dev_pager_hash(name_port) \
  149. (((vm_offset_t)(name_port) & 0xffffff) % DEV_PAGER_HASH_COUNT)
  150. void dev_pager_hash_init(void)
  151. {
  152. int i;
  153. vm_size_t size;
  154. size = sizeof(struct dev_pager_entry);
  155. kmem_cache_init(&dev_pager_hash_cache, "dev_pager_entry", size, 0,
  156. NULL, 0);
  157. for (i = 0; i < DEV_PAGER_HASH_COUNT; i++)
  158. queue_init(&dev_pager_hashtable[i]);
  159. simple_lock_init(&dev_pager_hash_lock);
  160. }
  161. void dev_pager_hash_insert(
  162. const ipc_port_t name_port,
  163. const dev_pager_t rec)
  164. {
  165. dev_pager_entry_t new_entry;
  166. new_entry = (dev_pager_entry_t) kmem_cache_alloc(&dev_pager_hash_cache);
  167. new_entry->name = name_port;
  168. new_entry->pager_rec = rec;
  169. simple_lock(&dev_pager_hash_lock);
  170. queue_enter(&dev_pager_hashtable[dev_pager_hash(name_port)],
  171. new_entry, dev_pager_entry_t, links);
  172. simple_unlock(&dev_pager_hash_lock);
  173. }
  174. void dev_pager_hash_delete(const ipc_port_t name_port)
  175. {
  176. queue_t bucket;
  177. dev_pager_entry_t entry;
  178. bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
  179. simple_lock(&dev_pager_hash_lock);
  180. for (entry = (dev_pager_entry_t)queue_first(bucket);
  181. !queue_end(bucket, &entry->links);
  182. entry = (dev_pager_entry_t)queue_next(&entry->links)) {
  183. if (entry->name == name_port) {
  184. queue_remove(bucket, entry, dev_pager_entry_t, links);
  185. break;
  186. }
  187. }
  188. simple_unlock(&dev_pager_hash_lock);
  189. if (entry)
  190. kmem_cache_free(&dev_pager_hash_cache, (vm_offset_t)entry);
  191. }
  192. dev_pager_t dev_pager_hash_lookup(const ipc_port_t name_port)
  193. {
  194. queue_t bucket;
  195. dev_pager_entry_t entry;
  196. dev_pager_t pager;
  197. bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
  198. simple_lock(&dev_pager_hash_lock);
  199. for (entry = (dev_pager_entry_t)queue_first(bucket);
  200. !queue_end(bucket, &entry->links);
  201. entry = (dev_pager_entry_t)queue_next(&entry->links)) {
  202. if (entry->name == name_port) {
  203. pager = entry->pager_rec;
  204. dev_pager_reference(pager);
  205. simple_unlock(&dev_pager_hash_lock);
  206. return (pager);
  207. }
  208. }
  209. simple_unlock(&dev_pager_hash_lock);
  210. return (DEV_PAGER_NULL);
  211. }
  212. kern_return_t device_pager_setup(
  213. const mach_device_t device,
  214. int prot,
  215. vm_offset_t offset,
  216. vm_size_t size,
  217. mach_port_t *pager)
  218. {
  219. dev_pager_t d;
  220. /*
  221. * Verify the device is indeed mappable
  222. */
  223. if (!device->dev_ops->d_mmap || (device->dev_ops->d_mmap == nomap))
  224. return (D_INVALID_OPERATION);
  225. /*
  226. * Allocate a structure to hold the arguments
  227. * and port to represent this object.
  228. */
  229. d = dev_pager_hash_lookup((ipc_port_t)device); /* HACK */
  230. if (d != DEV_PAGER_NULL) {
  231. *pager = (mach_port_t) ipc_port_make_send(d->pager);
  232. dev_pager_deallocate(d);
  233. return (D_SUCCESS);
  234. }
  235. d = (dev_pager_t) kmem_cache_alloc(&dev_pager_cache);
  236. if (d == DEV_PAGER_NULL)
  237. return (KERN_RESOURCE_SHORTAGE);
  238. simple_lock_init(&d->lock);
  239. d->ref_count = 1;
  240. /*
  241. * Allocate the pager port.
  242. */
  243. d->pager = ipc_port_alloc_kernel();
  244. if (d->pager == IP_NULL) {
  245. dev_pager_deallocate(d);
  246. return (KERN_RESOURCE_SHORTAGE);
  247. }
  248. d->client_count = 0;
  249. d->pager_request = IP_NULL;
  250. d->pager_name = IP_NULL;
  251. d->device = device;
  252. mach_device_reference(device);
  253. d->prot = prot;
  254. d->size = round_page(size);
  255. if (device->dev_ops->d_mmap == block_io_mmap) {
  256. d->type = DEV_PAGER_TYPE;
  257. } else {
  258. d->type = CHAR_PAGER_TYPE;
  259. }
  260. dev_pager_hash_insert(d->pager, d);
  261. dev_pager_hash_insert((ipc_port_t)device, d); /* HACK */
  262. *pager = (mach_port_t) ipc_port_make_send(d->pager);
  263. return (KERN_SUCCESS);
  264. }
  265. /*
  266. * Routine: device_pager_release
  267. * Purpose:
  268. * Relinquish any references or rights that were
  269. * associated with the result of a call to
  270. * device_pager_setup.
  271. */
  272. void device_pager_release(memory_object_t object)
  273. {
  274. if (MACH_PORT_VALID(object))
  275. ipc_port_release_send((ipc_port_t) object);
  276. }
  277. boolean_t device_pager_debug = FALSE;
  278. kern_return_t device_pager_data_request(
  279. const ipc_port_t pager,
  280. const ipc_port_t pager_request,
  281. vm_offset_t offset,
  282. vm_size_t length,
  283. vm_prot_t protection_required)
  284. {
  285. dev_pager_t ds;
  286. if (device_pager_debug)
  287. printf("(device_pager)data_request: pager=%p, offset=0x%lx, length=0x%x\n",
  288. pager, offset, length);
  289. ds = dev_pager_hash_lookup(pager);
  290. if (ds == DEV_PAGER_NULL)
  291. panic("(device_pager)data_request: lookup failed");
  292. if (ds->pager_request != pager_request)
  293. panic("(device_pager)data_request: bad pager_request");
  294. if (ds->type == CHAR_PAGER_TYPE) {
  295. vm_object_t object;
  296. object = vm_object_lookup(pager_request);
  297. if (object == VM_OBJECT_NULL) {
  298. (void) r_memory_object_data_error(pager_request,
  299. offset, length,
  300. KERN_FAILURE);
  301. dev_pager_deallocate(ds);
  302. return (KERN_SUCCESS);
  303. }
  304. vm_object_page_map(object,
  305. offset, length,
  306. device_map_page, (void *)ds);
  307. vm_object_deallocate(object);
  308. }
  309. else {
  310. panic("(device_pager)data_request: dev pager");
  311. }
  312. dev_pager_deallocate(ds);
  313. return (KERN_SUCCESS);
  314. }
  315. kern_return_t device_pager_copy(
  316. const ipc_port_t pager,
  317. const ipc_port_t pager_request,
  318. vm_offset_t offset,
  319. vm_size_t length,
  320. const ipc_port_t new_pager)
  321. {
  322. panic("(device_pager)copy: called");
  323. }
  324. kern_return_t
  325. device_pager_supply_completed(
  326. const ipc_port_t pager,
  327. const ipc_port_t pager_request,
  328. vm_offset_t offset,
  329. vm_size_t length,
  330. kern_return_t result,
  331. vm_offset_t error_offset)
  332. {
  333. panic("(device_pager)supply_completed: called");
  334. }
  335. kern_return_t
  336. device_pager_data_return(
  337. const ipc_port_t pager,
  338. const ipc_port_t pager_request,
  339. vm_offset_t offset,
  340. pointer_t addr,
  341. vm_size_t data_cnt,
  342. boolean_t dirty,
  343. boolean_t kernel_copy)
  344. {
  345. panic("(device_pager)data_return: called");
  346. }
  347. kern_return_t
  348. device_pager_change_completed(
  349. const ipc_port_t pager,
  350. boolean_t may_cache,
  351. memory_object_copy_strategy_t copy_strategy)
  352. {
  353. panic("(device_pager)change_completed: called");
  354. }
  355. /*
  356. * The mapping function takes a byte offset, but returns
  357. * a machine-dependent page frame number. We convert
  358. * that into something that the pmap module will
  359. * accept later.
  360. */
  361. vm_offset_t device_map_page(
  362. void *dsp,
  363. vm_offset_t offset)
  364. {
  365. dev_pager_t ds = (dev_pager_t) dsp;
  366. return pmap_phys_address(
  367. (*(ds->device->dev_ops->d_mmap))
  368. (ds->device->dev_number, offset, ds->prot));
  369. }
  370. kern_return_t device_pager_init_pager(
  371. const ipc_port_t pager,
  372. const ipc_port_t pager_request,
  373. const ipc_port_t pager_name,
  374. vm_size_t pager_page_size)
  375. {
  376. dev_pager_t ds;
  377. if (device_pager_debug)
  378. printf("(device_pager)init: pager=%p, request=%p, name=%p\n",
  379. pager, pager_request, pager_name);
  380. assert(pager_page_size == PAGE_SIZE);
  381. assert(IP_VALID(pager_request));
  382. assert(IP_VALID(pager_name));
  383. ds = dev_pager_hash_lookup(pager);
  384. assert(ds != DEV_PAGER_NULL);
  385. assert(ds->client_count == 0);
  386. assert(ds->pager_request == IP_NULL);
  387. assert(ds->pager_name == IP_NULL);
  388. ds->client_count = 1;
  389. /*
  390. * We save the send rights for the request and name ports.
  391. */
  392. ds->pager_request = pager_request;
  393. ds->pager_name = pager_name;
  394. if (ds->type == CHAR_PAGER_TYPE) {
  395. /*
  396. * Reply that the object is ready
  397. */
  398. (void) r_memory_object_ready(pager_request,
  399. FALSE, /* do not cache */
  400. MEMORY_OBJECT_COPY_NONE);
  401. } else {
  402. (void) r_memory_object_ready(pager_request,
  403. TRUE, /* cache */
  404. MEMORY_OBJECT_COPY_DELAY);
  405. }
  406. dev_pager_deallocate(ds);
  407. return (KERN_SUCCESS);
  408. }
  409. kern_return_t device_pager_terminate(
  410. const ipc_port_t pager,
  411. const ipc_port_t pager_request,
  412. const ipc_port_t pager_name)
  413. {
  414. dev_pager_t ds;
  415. assert(IP_VALID(pager_request));
  416. assert(IP_VALID(pager_name));
  417. ds = dev_pager_hash_lookup(pager);
  418. assert(ds != DEV_PAGER_NULL);
  419. assert(ds->client_count == 1);
  420. assert(ds->pager_request == pager_request);
  421. assert(ds->pager_name == pager_name);
  422. dev_pager_hash_delete(ds->pager);
  423. dev_pager_hash_delete((ipc_port_t)ds->device); /* HACK */
  424. mach_device_deallocate(ds->device);
  425. /* release the send rights we have saved from the init call */
  426. ipc_port_release_send(pager_request);
  427. ipc_port_release_send(pager_name);
  428. /* release the naked receive rights we just acquired */
  429. ipc_port_release_receive(pager_request);
  430. ipc_port_release_receive(pager_name);
  431. /* release the kernel's receive right for the pager port */
  432. ipc_port_dealloc_kernel(pager);
  433. /* once for ref from lookup, once to make it go away */
  434. dev_pager_deallocate(ds);
  435. dev_pager_deallocate(ds);
  436. return (KERN_SUCCESS);
  437. }
  438. kern_return_t device_pager_data_unlock(
  439. const ipc_port_t memory_object,
  440. const ipc_port_t memory_control_port,
  441. vm_offset_t offset,
  442. vm_size_t length,
  443. vm_prot_t desired_access)
  444. {
  445. panic("(device_pager)data_unlock: called");
  446. return (KERN_FAILURE);
  447. }
  448. kern_return_t device_pager_lock_completed(
  449. const ipc_port_t memory_object,
  450. const ipc_port_t pager_request_port,
  451. vm_offset_t offset,
  452. vm_size_t length)
  453. {
  454. panic("(device_pager)lock_completed: called");
  455. return (KERN_FAILURE);
  456. }
  457. void device_pager_init(void)
  458. {
  459. vm_size_t size;
  460. /*
  461. * Initialize cache of paging structures.
  462. */
  463. size = sizeof(struct dev_pager);
  464. kmem_cache_init(&dev_pager_cache, "dev_pager", size, 0,
  465. NULL, 0);
  466. /*
  467. * Initialize the name port hashing stuff.
  468. */
  469. dev_pager_hash_init();
  470. }