00001
00018 #include "pm.h"
00019 #include <minix/keymap.h>
00020 #include <minix/callnr.h>
00021 #include <minix/com.h>
00022 #include <minix/endpoint.h>
00023 #include <signal.h>
00024 #include <stdlib.h>
00025 #include <fcntl.h>
00026 #include <sys/resource.h>
00027 #include <string.h>
00028 #include "mproc.h"
00029 #include "param.h"
00030
00031 #include "../../kernel/const.h"
00032 #include "../../kernel/config.h"
00033 #include "../../kernel/type.h"
00034 #include "../../kernel/proc.h"
00035
00036 FORWARD _PROTOTYPE( void get_work, (void) );
00037 FORWARD _PROTOTYPE( void pm_init, (void) );
00038 FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
00039 FORWARD _PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks) );
00040 FORWARD _PROTOTYPE( void patch_mem_chunks, (struct memory *mem_chunks,
00041 struct mem_map *map_ptr) );
00042 FORWARD _PROTOTYPE( void do_x86_vm, (struct memory mem_chunks[NR_MEMS]) );
00043
00044 #define click_to_round_k(n) \
00045 ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
00046
00047
00048
00049
00050 PUBLIC int main()
00051 {
00052
00053 int result, s, proc_nr;
00054 struct mproc *rmp;
00055 sigset_t sigset;
00056
00057 pm_init();
00058
00059
00060 while (TRUE) {
00061 get_work();
00062
00063
00064 if (call_nr == SYN_ALARM) {
00065 pm_expire_timers(m_in.NOTIFY_TIMESTAMP);
00066 result = SUSPEND;
00067 } else if (call_nr == SYS_SIG) {
00068 sigset = m_in.NOTIFY_ARG;
00069 if (sigismember(&sigset, SIGKSIG)) {
00070 (void) ksig_pending();
00071 }
00072 result = SUSPEND;
00073 }
00074
00075 else if ((unsigned) call_nr >= NCALLS) {
00076 result = ENOSYS;
00077 } else {
00078 result = (*call_vec[call_nr])();
00079 }
00080
00081
00082 if (result != SUSPEND) setreply(who_p, result);
00083
00084 swap_in();
00085
00086
00087
00088
00089 for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
00090
00091
00092
00093
00094
00095 if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) ==
00096 (REPLY | IN_USE)) {
00097 if ((s=send(rmp->mp_endpoint, &rmp->mp_reply)) != OK) {
00098 printf("PM can't reply to %d (%s)\n",
00099 rmp->mp_endpoint, rmp->mp_name);
00100 panic(__FILE__, "PM can't reply", NO_NUM);
00101 }
00102 rmp->mp_flags &= ~REPLY;
00103 }
00104 }
00105 }
00106 return(OK);
00107 }
00108
00109
00110
00111
00112 PRIVATE void get_work()
00113 {
00114
00115 if (receive(ANY, &m_in) != OK)
00116 panic(__FILE__,"PM receive error", NO_NUM);
00117 who_e = m_in.m_source;
00118 if(pm_isokendpt(who_e, &who_p) != OK)
00119 panic(__FILE__, "PM got message from invalid endpoint", who_e);
00120 call_nr = m_in.m_type;
00121
00122
00123
00124
00125
00126 mp = &mproc[who_p < 0 ? PM_PROC_NR : who_p];
00127 if(who_p >= 0 && mp->mp_endpoint != who_e) {
00128 panic(__FILE__, "PM endpoint number out of sync with source",
00129 mp->mp_endpoint);
00130 }
00131 }
00132
00133
00134
00135
00136 PUBLIC void setreply(proc_nr, result)
00137 int proc_nr;
00138 int result;
00139 {
00140
00141
00142
00143
00144 register struct mproc *rmp = &mproc[proc_nr];
00145
00146 if(proc_nr < 0 || proc_nr >= NR_PROCS)
00147 panic(__FILE__,"setreply arg out of range", proc_nr);
00148
00149 rmp->mp_reply.reply_res = result;
00150 rmp->mp_flags |= REPLY;
00151
00152 if (rmp->mp_flags & ONSWAP)
00153 swap_inqueue(rmp);
00154 }
00155
00156
00157
00158
00159 PRIVATE void pm_init()
00160 {
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 int s;
00174 static struct boot_image image[NR_BOOT_PROCS];
00175 register struct boot_image *ip;
00176 static char core_sigs[] = { SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
00177 SIGEMT, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2 };
00178 static char ign_sigs[] = { SIGCHLD, SIGWINCH, SIGCONT };
00179 static char mess_sigs[] = { SIGTERM, SIGHUP, SIGABRT, SIGQUIT };
00180 register struct mproc *rmp;
00181 register int i;
00182 register char *sig_ptr;
00183 phys_clicks total_clicks, minix_clicks, free_clicks;
00184 message mess;
00185 struct mem_map mem_map[NR_LOCAL_SEGS];
00186 struct memory mem_chunks[NR_MEMS];
00187
00188
00189 for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) {
00190 tmr_inittimer(&rmp->mp_timer);
00191 }
00192
00193
00194
00195
00196 sigemptyset(&core_sset);
00197 for (sig_ptr = core_sigs; sig_ptr < core_sigs+sizeof(core_sigs); sig_ptr++)
00198 sigaddset(&core_sset, *sig_ptr);
00199 sigemptyset(&ign_sset);
00200 for (sig_ptr = ign_sigs; sig_ptr < ign_sigs+sizeof(ign_sigs); sig_ptr++)
00201 sigaddset(&ign_sset, *sig_ptr);
00202
00203
00204
00205
00206
00207 if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK)
00208 panic(__FILE__,"get monitor params failed",s);
00209 get_mem_chunks(mem_chunks);
00210 if ((s=sys_getkinfo(&kinfo)) != OK)
00211 panic(__FILE__,"get kernel info failed",s);
00212
00213
00214 if ((s=get_mem_map(SYSTASK, mem_map)) != OK)
00215 panic(__FILE__,"couldn't get memory map of SYSTASK",s);
00216 minix_clicks = (mem_map[S].mem_phys+mem_map[S].mem_len)-mem_map[T].mem_phys;
00217 patch_mem_chunks(mem_chunks, mem_map);
00218
00219
00220
00221
00222 if (OK != (s=sys_getimage(image)))
00223 panic(__FILE__,"couldn't get image table: %d\n", s);
00224 procs_in_use = 0;
00225 printf("Building process table:");
00226 for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {
00227 if (ip->proc_nr >= 0) {
00228 procs_in_use += 1;
00229
00230
00231 rmp = &mproc[ip->proc_nr];
00232 strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN);
00233 rmp->mp_parent = RS_PROC_NR;
00234 rmp->mp_nice = get_nice_value(ip->priority);
00235 sigemptyset(&rmp->mp_sig2mess);
00236 sigemptyset(&rmp->mp_ignore);
00237 sigemptyset(&rmp->mp_sigmask);
00238 sigemptyset(&rmp->mp_catch);
00239 if (ip->proc_nr == INIT_PROC_NR) {
00240 rmp->mp_procgrp = rmp->mp_pid = INIT_PID;
00241 rmp->mp_flags |= IN_USE;
00242 }
00243 else {
00244 rmp->mp_pid = get_free_pid();
00245 rmp->mp_flags |= IN_USE | DONT_SWAP | PRIV_PROC;
00246 for (sig_ptr = mess_sigs;
00247 sig_ptr < mess_sigs+sizeof(mess_sigs);
00248 sig_ptr++)
00249 sigaddset(&rmp->mp_sig2mess, *sig_ptr);
00250 }
00251
00252
00253 rmp->mp_endpoint = ip->endpoint;
00254
00255
00256 if ((s=get_mem_map(ip->proc_nr, rmp->mp_seg)) != OK)
00257 panic(__FILE__,"couldn't get process entry",s);
00258 if (rmp->mp_seg[T].mem_len != 0) rmp->mp_flags |= SEPARATE;
00259 minix_clicks += rmp->mp_seg[S].mem_phys +
00260 rmp->mp_seg[S].mem_len - rmp->mp_seg[T].mem_phys;
00261 patch_mem_chunks(mem_chunks, rmp->mp_seg);
00262
00263
00264 mess.PR_SLOT = ip->proc_nr;
00265 mess.PR_PID = rmp->mp_pid;
00266 mess.PR_ENDPT = rmp->mp_endpoint;
00267 if (OK != (s=send(FS_PROC_NR, &mess)))
00268 panic(__FILE__,"can't sync up with FS", s);
00269 printf(" %s", ip->proc_name);
00270 }
00271 }
00272 printf(".\n");
00273
00274
00275 mproc[PM_PROC_NR].mp_pid = PM_PID;
00276 mproc[RS_PROC_NR].mp_parent = INIT_PROC_NR;
00277 sigfillset(&mproc[PM_PROC_NR].mp_ignore);
00278
00279
00280 mess.PR_ENDPT = NONE;
00281 if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK)
00282 panic(__FILE__,"can't sync up with FS", NO_NUM);
00283
00284 #if ENABLE_BOOTDEV
00285
00286 if (kinfo.bootdev_size > 0) {
00287 mem_map[T].mem_phys = kinfo.bootdev_base >> CLICK_SHIFT;
00288 mem_map[T].mem_len = 0;
00289 mem_map[D].mem_len = (kinfo.bootdev_size+CLICK_SIZE-1) >> CLICK_SHIFT;
00290 patch_mem_chunks(mem_chunks, mem_map);
00291 }
00292 #endif
00293
00294
00295 do_x86_vm(mem_chunks);
00296
00297
00298 printf("Physical memory:");
00299 mem_init(mem_chunks, &free_clicks);
00300 total_clicks = minix_clicks + free_clicks;
00301 printf(" total %u KB,", click_to_round_k(total_clicks));
00302 printf(" system %u KB,", click_to_round_k(minix_clicks));
00303 printf(" free %u KB.\n", click_to_round_k(free_clicks));
00304 }
00305
00306
00307
00308
00309 PRIVATE int get_nice_value(queue)
00310 int queue;
00311 {
00312
00313
00314
00315
00316 int nice_val = (queue - USER_Q) * (PRIO_MAX-PRIO_MIN+1) /
00317 (MIN_USER_Q-MAX_USER_Q+1);
00318 if (nice_val > PRIO_MAX) nice_val = PRIO_MAX;
00319 if (nice_val < PRIO_MIN) nice_val = PRIO_MIN;
00320 return nice_val;
00321 }
00322
00323 #if _WORD_SIZE == 2
00324
00325
00326
00327
00328
00329 #define MAX_REAL 0x00100000L
00330 #define MAX_16BIT (0xFFF0L << CLICK_SHIFT)
00331 #endif
00332
00333
00334
00335
00336 PRIVATE void get_mem_chunks(mem_chunks)
00337 struct memory *mem_chunks;
00338 {
00339
00340
00341
00342
00343
00344 long base, size, limit;
00345 char *s, *end;
00346 int i, done = 0;
00347 struct memory *memp;
00348 #if _WORD_SIZE == 2
00349 unsigned long max_address;
00350 struct machine machine;
00351 if (OK != (i=sys_getmachine(&machine)))
00352 panic(__FILE__, "sys_getmachine failed", i);
00353 #endif
00354
00355
00356 for (i = 0; i < NR_MEMS; i++) {
00357 memp = &mem_chunks[i];
00358 memp->base = memp->size = 0;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367 s = find_param("memory");
00368 for (i = 0; i < NR_MEMS && !done; i++) {
00369 memp = &mem_chunks[i];
00370 base = size = 0;
00371 if (*s != 0) {
00372
00373
00374 base = strtoul(s, &end, 0x10);
00375 if (end != s && *end == ':') s = ++end;
00376 else *s=0;
00377
00378
00379 size = strtoul(s, &end, 0x10);
00380 if (end != s && *end == ',') s = ++end;
00381 else done = 1;
00382 }
00383 limit = base + size;
00384 #if _WORD_SIZE == 2
00385 max_address = machine.protected ? MAX_16BIT : MAX_REAL;
00386 if (limit > max_address) limit = max_address;
00387 #endif
00388 base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
00389 limit &= ~(long)(CLICK_SIZE-1);
00390 if (limit <= base) continue;
00391 memp->base = base >> CLICK_SHIFT;
00392 memp->size = (limit - base) >> CLICK_SHIFT;
00393 }
00394 }
00395
00396
00397
00398
00399 PRIVATE void patch_mem_chunks(mem_chunks, map_ptr)
00400 struct memory *mem_chunks;
00401 struct mem_map *map_ptr;
00402 {
00403
00404
00405
00406
00407
00408
00409 struct memory *memp;
00410 for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) {
00411 if (memp->base == map_ptr[T].mem_phys) {
00412 memp->base += map_ptr[T].mem_len + map_ptr[D].mem_len;
00413 memp->size -= map_ptr[T].mem_len + map_ptr[D].mem_len;
00414 }
00415 }
00416 }
00417
00418 #define PAGE_SIZE 4096
00419 #define PAGE_TABLE_COVER (1024*PAGE_SIZE)
00420
00421
00422
00423 PRIVATE void do_x86_vm(mem_chunks)
00424 struct memory mem_chunks[NR_MEMS];
00425 {
00426 phys_bytes high, bytes;
00427 phys_clicks clicks, base_click;
00428 unsigned pages;
00429 int i, r;
00430
00431
00432 high= 0;
00433 for (i= 0; i<NR_MEMS; i++)
00434 {
00435 if (mem_chunks[i].size == 0)
00436 continue;
00437 if (mem_chunks[i].base + mem_chunks[i].size > high)
00438 high= mem_chunks[i].base + mem_chunks[i].size;
00439 }
00440
00441 high <<= CLICK_SHIFT;
00442 #if VERBOSE_VM
00443 printf("do_x86_vm: found high 0x%x\n", high);
00444 #endif
00445
00446
00447
00448
00449 pages= 1 + (high + PAGE_TABLE_COVER-1)/PAGE_TABLE_COVER + 1;
00450 bytes= pages*PAGE_SIZE;
00451 clicks= (bytes + CLICK_SIZE-1) >> CLICK_SHIFT;
00452
00453 #if VERBOSE_VM
00454 printf("do_x86_vm: need %d pages\n", pages);
00455 printf("do_x86_vm: need %d bytes\n", bytes);
00456 printf("do_x86_vm: need %d clicks\n", clicks);
00457 #endif
00458
00459 for (i= 0; i<NR_MEMS; i++)
00460 {
00461 if (mem_chunks[i].size <= clicks)
00462 continue;
00463 break;
00464 }
00465 if (i >= NR_MEMS)
00466 panic("PM", "not enough memory for VM page tables?", NO_NUM);
00467 base_click= mem_chunks[i].base;
00468 mem_chunks[i].base += clicks;
00469 mem_chunks[i].size -= clicks;
00470
00471 #if VERBOSE_VM
00472 printf("do_x86_vm: using 0x%x clicks @ 0x%x\n", clicks, base_click);
00473 #endif
00474 r= sys_vm_setbuf(base_click << CLICK_SHIFT, clicks << CLICK_SHIFT,
00475 high);
00476 if (r != 0)
00477 printf("do_x86_vm: sys_vm_setbuf failed: %d\n", r);
00478 }