651 |
#endif |
#endif |
652 |
dp_map_t map; /* block map */ |
dp_map_t map; /* block map */ |
653 |
vm_size_t size; /* size of paging object, in pages */ |
vm_size_t size; /* size of paging object, in pages */ |
654 |
|
vm_size_t limit; /* limit (bytes) allowed to grow to */ |
655 |
p_index_t cur_partition; |
p_index_t cur_partition; |
656 |
#ifdef CHECKSUM |
#ifdef CHECKSUM |
657 |
vm_offset_t *checksum; /* checksum - parallel to block map */ |
vm_offset_t *checksum; /* checksum - parallel to block map */ |
740 |
} |
} |
741 |
pager->map = mapptr; |
pager->map = mapptr; |
742 |
pager->size = size; |
pager->size = size; |
743 |
|
pager->limit = (vm_size_t)-1; |
744 |
|
|
745 |
#ifdef CHECKSUM |
#ifdef CHECKSUM |
746 |
if (INDIRECT_PAGEMAP(size)) { |
if (INDIRECT_PAGEMAP(size)) { |
915 |
pager->writer = FALSE; |
pager->writer = FALSE; |
916 |
#endif |
#endif |
917 |
mutex_unlock(&pager->lock); |
mutex_unlock(&pager->lock); |
918 |
|
#if 0 |
919 |
ddprintf ("pager_extend 1 mapptr %x [3b] = %x\n", new_mapptr, |
ddprintf ("pager_extend 1 mapptr %x [3b] = %x\n", new_mapptr, |
920 |
new_mapptr[0x3b]); |
new_mapptr[0x3b]); |
921 |
if (new_mapptr[0x3b].indirect > 0x10000 |
if (new_mapptr[0x3b].indirect > 0x10000 |
922 |
&& new_mapptr[0x3b].indirect != NO_BLOCK) |
&& new_mapptr[0x3b].indirect != NO_BLOCK) |
923 |
panic ("debug panic"); |
panic ("debug panic"); |
924 |
|
#endif |
925 |
return; |
return; |
926 |
} |
} |
927 |
|
|
945 |
kfree((char *)old_mapptr, PAGEMAP_SIZE(old_size)); |
kfree((char *)old_mapptr, PAGEMAP_SIZE(old_size)); |
946 |
old_mapptr = new_mapptr; |
old_mapptr = new_mapptr; |
947 |
|
|
948 |
|
#if 0 |
949 |
ddprintf ("pager_extend 2 mapptr %x [3b] = %x\n", new_mapptr, |
ddprintf ("pager_extend 2 mapptr %x [3b] = %x\n", new_mapptr, |
950 |
new_mapptr[0x3b]); |
new_mapptr[0x3b]); |
951 |
if (new_mapptr[0x3b].indirect > 0x10000 |
if (new_mapptr[0x3b].indirect > 0x10000 |
952 |
&& new_mapptr[0x3b].indirect != NO_BLOCK) |
&& new_mapptr[0x3b].indirect != NO_BLOCK) |
953 |
panic ("debug panic"); |
panic ("debug panic"); |
954 |
|
#endif |
955 |
|
|
956 |
/* |
/* |
957 |
* Now allocate indirect map. |
* Now allocate indirect map. |
1021 |
mutex_unlock(&pager->lock); |
mutex_unlock(&pager->lock); |
1022 |
} |
} |
1023 |
|
|
1024 |
|
/* Truncate a memory object. First, any pages between the new size |
1025 |
|
and the (larger) old size are deallocated. Then, the size of |
1026 |
|
the pagemap may be reduced, an indirect map may be turned into |
1027 |
|
a direct map. |
1028 |
|
|
1029 |
|
The pager must be locked by the caller. */ |
1030 |
|
static void |
1031 |
|
pager_truncate(dpager_t pager, vm_size_t new_size) /* in pages */ |
1032 |
|
{ |
1033 |
|
dp_map_t new_mapptr; |
1034 |
|
dp_map_t old_mapptr; |
1035 |
|
int i; |
1036 |
|
vm_size_t old_size; |
1037 |
|
|
1038 |
|
/* This deallocates the pages necessary to truncate a direct map |
1039 |
|
previously of size NEW_SIZE to the smaller size OLD_SIZE. */ |
1040 |
|
inline void dealloc_direct (dp_map_t mapptr, |
1041 |
|
vm_size_t old_size, vm_size_t new_size) |
1042 |
|
{ |
1043 |
|
vm_size_t i; |
1044 |
|
for (i = new_size; i < old_size; ++i) |
1045 |
|
{ |
1046 |
|
const union dp_map entry = mapptr[i]; |
1047 |
|
pager_dealloc_page(entry.block.p_index, entry.block.p_offset, |
1048 |
|
TRUE); |
1049 |
|
invalidate_block(mapptr[i]); |
1050 |
|
} |
1051 |
|
} |
1052 |
|
|
1053 |
|
old_size = pager->size; |
1054 |
|
|
1055 |
|
if (INDIRECT_PAGEMAP(old_size)) |
1056 |
|
{ |
1057 |
|
/* First handle the entire second-levels blocks that are being freed. */ |
1058 |
|
for (i = INDIRECT_PAGEMAP_ENTRIES(new_size); |
1059 |
|
i < INDIRECT_PAGEMAP_ENTRIES(old_size); |
1060 |
|
++i) |
1061 |
|
{ |
1062 |
|
const dp_map_t mapptr = pager->map[i].indirect; |
1063 |
|
pager->map[i].indirect = (dp_map_t)0; |
1064 |
|
dealloc_direct (mapptr, PAGEMAP_ENTRIES, 0); |
1065 |
|
kfree ((char *)mapptr, PAGEMAP_SIZE(PAGEMAP_ENTRIES)); |
1066 |
|
} |
1067 |
|
|
1068 |
|
/* Now truncate what's now the final nonempty direct block. */ |
1069 |
|
dealloc_direct (pager->map[(new_size - 1) / PAGEMAP_ENTRIES].indirect, |
1070 |
|
old_size & (PAGEMAP_ENTRIES - 1), |
1071 |
|
new_size & (PAGEMAP_ENTRIES - 1)); |
1072 |
|
|
1073 |
|
if (INDIRECT_PAGEMAP (new_size)) |
1074 |
|
{ |
1075 |
|
if (INDIRECT_PAGEMAP_SIZE (new_size) >= vm_page_size) |
1076 |
|
/* XXX we know how kalloc.c works; avoid copying. */ |
1077 |
|
kfree ((char *) round_page ((vm_address_t) pager->map |
1078 |
|
+ INDIRECT_PAGEMAP_SIZE (new_size)), |
1079 |
|
round_page (INDIRECT_PAGEMAP_SIZE (old_size)) |
1080 |
|
- round_page (INDIRECT_PAGEMAP_SIZE (new_size))); |
1081 |
|
else |
1082 |
|
{ |
1083 |
|
const dp_map_t old_mapptr = pager->map; |
1084 |
|
pager->map = (dp_map_t) kalloc (INDIRECT_PAGEMAP_SIZE(new_size)); |
1085 |
|
memcpy (pager->map, old_mapptr, INDIRECT_PAGEMAP_SIZE(old_size)); |
1086 |
|
kfree ((char *) old_mapptr, INDIRECT_PAGEMAP_SIZE (old_size)); |
1087 |
|
} |
1088 |
|
} |
1089 |
|
else |
1090 |
|
{ |
1091 |
|
/* We are truncating to a size small enough that it goes to using |
1092 |
|
a one-level map. We already have that map, as the first and only |
1093 |
|
nonempty element in our indirect map. */ |
1094 |
|
const dp_map_t mapptr = pager->map[0].indirect; |
1095 |
|
kfree((char *)pager->map, INDIRECT_PAGEMAP_SIZE(old_size)); |
1096 |
|
pager->map = mapptr; |
1097 |
|
old_size = PAGEMAP_ENTRIES; |
1098 |
|
} |
1099 |
|
} |
1100 |
|
|
1101 |
|
if (new_size == 0) |
1102 |
|
new_size = 1; |
1103 |
|
|
1104 |
|
if (! INDIRECT_PAGEMAP(old_size)) |
1105 |
|
{ |
1106 |
|
/* First deallocate pages in the truncated region. */ |
1107 |
|
dealloc_direct (pager->map, old_size, new_size); |
1108 |
|
/* Now reduce the size of the direct map itself. We don't bother |
1109 |
|
with kalloc/kfree if it's not shrinking enough that kalloc.c |
1110 |
|
would actually use less. */ |
1111 |
|
if (PAGEMAP_SIZE (new_size) <= PAGEMAP_SIZE (old_size) / 2) |
1112 |
|
{ |
1113 |
|
const dp_map_t old_mapptr = pager->map; |
1114 |
|
pager->map = (dp_map_t) kalloc (PAGEMAP_SIZE (new_size)); |
1115 |
|
memcpy (pager->map, old_mapptr, PAGEMAP_SIZE (old_size)); |
1116 |
|
kfree ((char *) old_mapptr, PAGEMAP_SIZE (old_size)); |
1117 |
|
} |
1118 |
|
} |
1119 |
|
|
1120 |
|
pager->size = new_size; |
1121 |
|
|
1122 |
|
#ifdef CHECKSUM |
1123 |
|
#error write me |
1124 |
|
#endif /* CHECKSUM */ |
1125 |
|
} |
1126 |
|
|
1127 |
|
|
1128 |
/* |
/* |
1129 |
* Given an offset within a paging object, find the |
* Given an offset within a paging object, find the |
1130 |
* corresponding block within the paging partition. |
* corresponding block within the paging partition. |
1819 |
{ |
{ |
1820 |
return ( ! no_block(pager_read_offset(ds, offset)) ); |
return ( ! no_block(pager_read_offset(ds, offset)) ); |
1821 |
} |
} |
|
|
|
1822 |
/* |
/* |
1823 |
|
|
1824 |
*/ |
*/ |
1846 |
unsigned int readers; /* Reads in progress */ |
unsigned int readers; /* Reads in progress */ |
1847 |
unsigned int writers; /* Writes in progress */ |
unsigned int writers; /* Writes in progress */ |
1848 |
|
|
1849 |
|
/* This is the reply port of an outstanding |
1850 |
|
default_pager_object_set_size call. */ |
1851 |
|
mach_port_t lock_request; |
1852 |
|
|
1853 |
unsigned int errors; /* Pageout error count */ |
unsigned int errors; /* Pageout error count */ |
1854 |
struct dpager dpager; /* Actual pager */ |
struct dpager dpager; /* Actual pager */ |
1855 |
}; |
}; |
2182 |
|
|
2183 |
/* We catch exceptions on ourself & startup using this port. */ |
/* We catch exceptions on ourself & startup using this port. */ |
2184 |
mach_port_t default_pager_exception_port; |
mach_port_t default_pager_exception_port; |
|
/* We receive bootstrap requests on this port. */ |
|
|
mach_port_t default_pager_bootstrap_port; |
|
2185 |
|
|
2186 |
mach_port_t default_pager_internal_set; /* Port set for internal objects. */ |
mach_port_t default_pager_internal_set; /* Port set for internal objects. */ |
2187 |
mach_port_t default_pager_external_set; /* Port set for external objects. */ |
mach_port_t default_pager_external_set; /* Port set for external objects. */ |
2648 |
goto done; |
goto done; |
2649 |
} |
} |
2650 |
|
|
2651 |
rc = default_read(&ds->dpager, dpt->dpt_buffer, |
if (offset >= ds->dpager.limit) |
2652 |
vm_page_size, offset, |
rc = PAGER_ERROR; |
2653 |
&addr, protection_required & VM_PROT_WRITE); |
else |
2654 |
|
rc = default_read(&ds->dpager, dpt->dpt_buffer, |
2655 |
|
vm_page_size, offset, |
2656 |
|
&addr, protection_required & VM_PROT_WRITE); |
2657 |
|
|
2658 |
switch (rc) { |
switch (rc) { |
2659 |
case PAGER_SUCCESS: |
case PAGER_SUCCESS: |
2876 |
return KERN_FAILURE; |
return KERN_FAILURE; |
2877 |
} |
} |
2878 |
|
|
2879 |
|
/* We get this when our memory_object_lock_request has completed |
2880 |
|
after we truncated an object. */ |
2881 |
kern_return_t |
kern_return_t |
2882 |
seqnos_memory_object_lock_completed(pager, seqno, pager_request, |
seqnos_memory_object_lock_completed (memory_object_t pager, |
2883 |
offset, length) |
mach_port_seqno_t seqno, |
2884 |
memory_object_t pager; |
mach_port_t pager_request, |
2885 |
mach_port_seqno_t seqno; |
vm_offset_t offset, |
2886 |
mach_port_t pager_request; |
vm_size_t length) |
|
vm_offset_t offset; |
|
|
vm_size_t length; |
|
2887 |
{ |
{ |
2888 |
#ifdef lint |
default_pager_t ds; |
|
pager++; seqno++; pager_request++; offset++; length++; |
|
|
#endif /* lint */ |
|
2889 |
|
|
2890 |
panic("%slock_completed",my_name); |
ds = pager_port_lookup(pager); |
2891 |
return(KERN_FAILURE); |
assert(ds != DEFAULT_PAGER_NULL); |
2892 |
|
|
2893 |
|
pager_port_lock(ds, seqno); |
2894 |
|
pager_port_wait_for_readers(ds); |
2895 |
|
pager_port_wait_for_writers(ds); |
2896 |
|
|
2897 |
|
/* Now that any in-core pages have been flushed, we can apply |
2898 |
|
the limit to prevent any new page-ins. */ |
2899 |
|
assert (page_aligned (offset)); |
2900 |
|
ds->dpager.limit = offset; |
2901 |
|
|
2902 |
|
default_pager_object_set_size_reply (ds->lock_request, KERN_SUCCESS); |
2903 |
|
ds->lock_request = MACH_PORT_NULL; |
2904 |
|
|
2905 |
|
if (ds->dpager.size > ds->dpager.limit / vm_page_size) |
2906 |
|
/* Deallocate the old backing store pages and shrink the page map. */ |
2907 |
|
pager_truncate (&ds->dpager, ds->dpager.limit / vm_page_size); |
2908 |
|
|
2909 |
|
pager_port_unlock(ds, seqno); |
2910 |
|
|
2911 |
|
return KERN_SUCCESS; |
2912 |
} |
} |
2913 |
|
|
2914 |
kern_return_t |
kern_return_t |
3029 |
rval = |
rval = |
3030 |
(seqnos_memory_object_server(in, out) || |
(seqnos_memory_object_server(in, out) || |
3031 |
seqnos_memory_object_default_server(in, out) || |
seqnos_memory_object_default_server(in, out) || |
3032 |
default_pager_notify_server(in, out)); |
default_pager_notify_server(in, out) || |
3033 |
|
default_pager_server(in, out)); |
3034 |
ddprintf ("DPAGER DEMUX OBJECT DONE <%p>: %d\n", in, in->msgh_id); |
ddprintf ("DPAGER DEMUX OBJECT DONE <%p>: %d\n", in, in->msgh_id); |
3035 |
return rval; |
return rval; |
3036 |
} |
} |
3062 |
*/ |
*/ |
3063 |
|
|
3064 |
return exc_server(in, out); |
return exc_server(in, out); |
|
} else if (in->msgh_local_port == default_pager_bootstrap_port) { |
|
|
/* |
|
|
* We receive bootstrap requests |
|
|
* from the startup task. |
|
|
*/ |
|
|
|
|
|
if (in->msgh_id == 999999) { |
|
|
/* compatibility for old bootstrap interface */ |
|
|
|
|
|
bootstrap_compat(in, out); |
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
return bootstrap_server(in, out); |
|
3065 |
} else { |
} else { |
3066 |
panic(my_name); |
panic(my_name); |
3067 |
return FALSE; |
return FALSE; |
3206 |
panic(my_name); |
panic(my_name); |
3207 |
|
|
3208 |
/* |
/* |
|
* Initialize the bootstrap port. |
|
|
*/ |
|
|
kr = mach_port_allocate(default_pager_self, MACH_PORT_RIGHT_RECEIVE, |
|
|
&default_pager_bootstrap_port); |
|
|
if (kr != KERN_SUCCESS) |
|
|
panic(my_name); |
|
|
|
|
|
/* |
|
3209 |
* Arrange for wiring privileges. |
* Arrange for wiring privileges. |
3210 |
*/ |
*/ |
3211 |
wire_setup(host_port); |
wire_setup(host_port); |
3280 |
if (kr != KERN_SUCCESS) |
if (kr != KERN_SUCCESS) |
3281 |
panic(my_name); |
panic(my_name); |
3282 |
|
|
|
kr = mach_port_move_member(default_pager_self, |
|
|
default_pager_bootstrap_port, |
|
|
default_pager_default_set); |
|
|
if (kr != KERN_SUCCESS) |
|
|
panic(my_name); |
|
|
|
|
3283 |
/* |
/* |
3284 |
* Now we create the threads that will actually |
* Now we create the threads that will actually |
3285 |
* manage objects. |
* manage objects. |
3705 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
3706 |
} |
} |
3707 |
|
|
3708 |
|
|
3709 |
|
kern_return_t |
3710 |
|
default_pager_object_set_size(mach_port_t pager, |
3711 |
|
mach_port_seqno_t seqno, |
3712 |
|
mach_port_t reply_to, |
3713 |
|
vm_size_t limit) |
3714 |
|
{ |
3715 |
|
kern_return_t kr; |
3716 |
|
default_pager_t ds; |
3717 |
|
|
3718 |
|
ds = pager_port_lookup(pager); |
3719 |
|
if (ds == DEFAULT_PAGER_NULL) |
3720 |
|
return KERN_INVALID_ARGUMENT; |
3721 |
|
|
3722 |
|
pager_port_lock(ds, seqno); |
3723 |
|
pager_port_check_request(ds, reply_to); |
3724 |
|
pager_port_wait_for_readers(ds); |
3725 |
|
pager_port_wait_for_writers(ds); |
3726 |
|
|
3727 |
|
limit = round_page (limit); |
3728 |
|
if (ds->dpager.size <= limit / vm_page_size) |
3729 |
|
{ |
3730 |
|
/* The limit has not been exceeded heretofore. Just change it. */ |
3731 |
|
ds->dpager.limit = limit; |
3732 |
|
kr = KERN_SUCCESS; |
3733 |
|
} |
3734 |
|
else if (ds->lock_request == MACH_PORT_NULL) |
3735 |
|
{ |
3736 |
|
/* Tell the kernel to flush from core all the pages being removed. |
3737 |
|
We will get the memory_object_lock_completed callback when they |
3738 |
|
have been flushed. We handle that by completing the limit update |
3739 |
|
and posting the reply to the pending truncation. */ |
3740 |
|
kr = memory_object_lock_request (ds->pager_request, |
3741 |
|
limit, |
3742 |
|
ds->dpager.size * vm_page_size - limit, |
3743 |
|
MEMORY_OBJECT_RETURN_NONE, TRUE, |
3744 |
|
VM_PROT_ALL, ds->pager); |
3745 |
|
if (kr != KERN_SUCCESS) |
3746 |
|
panic ("memory_object_lock_request: %d", kr); |
3747 |
|
ds->lock_request = reply_to; |
3748 |
|
kr = MIG_NO_REPLY; |
3749 |
|
} |
3750 |
|
else |
3751 |
|
/* There is already another call in progress. Tough titties. */ |
3752 |
|
kr = KERN_FAILURE; |
3753 |
|
|
3754 |
|
pager_port_unlock(ds, seqno); |
3755 |
|
|
3756 |
|
return kr; |
3757 |
|
} |
3758 |
|
|
3759 |
/* |
/* |
3760 |
* Add/remove extra paging space |
* Add/remove extra paging space |
3761 |
*/ |
*/ |
3903 |
|
|
3904 |
return KERN_FAILURE; |
return KERN_FAILURE; |
3905 |
} |
} |
|
|
|
|
/* |
|
|
* Handle bootstrap requests. |
|
|
*/ |
|
|
|
|
|
kern_return_t |
|
|
do_bootstrap_privileged_ports(bootstrap, hostp, devicep) |
|
|
mach_port_t bootstrap; |
|
|
mach_port_t *hostp, *devicep; |
|
|
{ |
|
|
*hostp = bootstrap_master_host_port; |
|
|
*devicep = bootstrap_master_device_port; |
|
|
return KERN_SUCCESS; |
|
|
} |
|
|
|
|
|
void |
|
|
bootstrap_compat(in, out) |
|
|
mach_msg_header_t *in, *out; |
|
|
{ |
|
|
mig_reply_header_t *reply = (mig_reply_header_t *) out; |
|
|
mach_msg_return_t mr; |
|
|
|
|
|
struct imsg { |
|
|
mach_msg_header_t hdr; |
|
|
mach_msg_type_t port_desc_1; |
|
|
mach_port_t port_1; |
|
|
mach_msg_type_t port_desc_2; |
|
|
mach_port_t port_2; |
|
|
} imsg; |
|
|
|
|
|
/* |
|
|
* Send back the host and device ports. |
|
|
*/ |
|
|
|
|
|
imsg.hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | |
|
|
MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(in->msgh_bits), 0); |
|
|
/* msgh_size doesn't need to be initialized */ |
|
|
imsg.hdr.msgh_remote_port = in->msgh_remote_port; |
|
|
imsg.hdr.msgh_local_port = MACH_PORT_NULL; |
|
|
/* msgh_seqno doesn't need to be initialized */ |
|
|
imsg.hdr.msgh_id = in->msgh_id + 100; /* this is a reply msg */ |
|
|
|
|
|
imsg.port_desc_1.msgt_name = MACH_MSG_TYPE_COPY_SEND; |
|
|
imsg.port_desc_1.msgt_size = (sizeof(mach_port_t) * 8); |
|
|
imsg.port_desc_1.msgt_number = 1; |
|
|
imsg.port_desc_1.msgt_inline = TRUE; |
|
|
imsg.port_desc_1.msgt_longform = FALSE; |
|
|
imsg.port_desc_1.msgt_deallocate = FALSE; |
|
|
imsg.port_desc_1.msgt_unused = 0; |
|
|
|
|
|
imsg.port_1 = bootstrap_master_host_port; |
|
|
|
|
|
imsg.port_desc_2 = imsg.port_desc_1; |
|
|
|
|
|
imsg.port_2 = bootstrap_master_device_port; |
|
|
|
|
|
/* |
|
|
* Send the reply message. |
|
|
* (mach_msg_server can not do this, because the reply |
|
|
* is not in standard format.) |
|
|
*/ |
|
|
|
|
|
mr = mach_msg(&imsg.hdr, MACH_SEND_MSG, |
|
|
sizeof imsg, 0, MACH_PORT_NULL, |
|
|
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); |
|
|
if (mr != MACH_MSG_SUCCESS) |
|
|
(void) mach_port_deallocate(default_pager_self, |
|
|
imsg.hdr.msgh_remote_port); |
|
|
|
|
|
/* |
|
|
* Tell mach_msg_server to do nothing. |
|
|
*/ |
|
|
|
|
|
reply->RetCode = MIG_NO_REPLY; |
|
|
} |
|
|
|
|
|
#ifdef mips |
|
|
/* |
|
|
* set_ras_address for default pager |
|
|
* Default pager does not have emulator support |
|
|
* so it needs a local version of set_ras_address. |
|
|
*/ |
|
|
int |
|
|
set_ras_address(basepc, boundspc) |
|
|
vm_offset_t basepc; |
|
|
vm_offset_t boundspc; |
|
|
{ |
|
|
kern_return_t status; |
|
|
|
|
|
status = task_ras_control(mach_task_self(), basepc, boundspc, |
|
|
TASK_RAS_CONTROL_INSTALL_ONE); |
|
|
if (status != KERN_SUCCESS) |
|
|
return -1; |
|
|
return 0; |
|
|
} |
|
|
#endif |
|