pc.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:13k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include <conio.h>
  6. #include <dir.h>
  7. #include <dos.h>
  8. #include <io.h>
  9. #include <sys/stat.h>
  10. #include <string.h>
  11. #include <process.h>
  12. #include <fcntl.h>
  13. /*#include <alloc.h> */
  14. #include <stdarg.h>
  15. #include <bios.h>
  16. #include <time.h>
  17. #include "global.h"
  18. #include "mbuf.h"
  19. #include "proc.h"
  20. #include "iface.h"
  21. #include "internet.h"
  22. #include "session.h"
  23. #include "socket.h"
  24. #include "usock.h"
  25. #include "cmdparse.h"
  26. #include "nospc.h"
  27. #include "display.h"
  28. static void statline(struct display *dp,struct session *sp);
  29. extern int Curdisp;
  30. extern struct proc *Display;
  31. unsigned _stklen = 8192;
  32. int Tick;
  33. static int32 Clock;
  34. extern INTERRUPT (*Kbvec)();
  35. /* This flag is set by setirq() if IRQ 8-15 is used, indicating
  36.  * that the machine is a PC/AT with a second 8259 interrupt controller.
  37.  * If this flag is set, the interrupt return code in pcgen.asm will
  38.  * send an End of Interrupt command to the second 8259 as well as the
  39.  * first.
  40.  */
  41. #ifdef CPU386
  42. int Isat = 1;
  43. #else
  44. int Isat;
  45. #endif
  46. static int saved_break;
  47. int
  48. errhandler(errval,ax,bp,si)
  49. int errval,ax,bp,si;
  50. {
  51. return 3; /* Fail the system call */
  52. }
  53. /* Called at startup time to set up console I/O, memory heap */
  54. void
  55. ioinit()
  56. {
  57. union REGS inregs;
  58. /* Increase the size of the file table.
  59.  * Note: this causes MS-DOS
  60.  * to allocate a block of memory to hold the larger file table.
  61.  * By default, this happens right after our program, which means
  62.  * any further sbrk() calls from morecore (called from malloc)
  63.  * will fail. Hence there is now code in alloc.c that can call
  64.  * the MS-DOS allocmem() function to grab additional MS-DOS
  65.  * memory blocks that are not contiguous with the program and
  66.  * put them on the heap.
  67.  */
  68. inregs.h.ah = 0x67;
  69. inregs.x.bx = Nfiles; /* Up to the base of the socket numbers */
  70. intdos(&inregs,&inregs);
  71. /* Allocate space for the fd reference count table */
  72. Refcnt = (unsigned *)calloc(sizeof(unsigned),Nfiles);
  73. Refcnt[3] = 1;
  74. Refcnt[4] = 1;
  75. _close(3);
  76. _close(4);
  77. /* Fail all I/O errors */
  78. harderr(errhandler);
  79. saved_break = getcbrk();
  80. setcbrk(0);
  81. /* Link timer handler into timer interrupt chain */
  82. chtimer(btick);
  83. /* Find out what multitasker we're running under, if any */
  84. chktasker();
  85. /* Hook keyboard interrupt */
  86. Kbvec = getirq(KBIRQ);
  87. setirq(KBIRQ,kbint);
  88. }
  89. /* Called just before exiting to restore console state */
  90. void
  91. iostop()
  92. {
  93. struct iface *ifp,*iftmp;
  94. void (**fp)(void);
  95. setcbrk(saved_break);
  96. for(ifp = Ifaces;ifp != NULL;ifp = iftmp){
  97. iftmp = ifp->next;
  98. if_detach(ifp);
  99. }
  100. /* Call list of shutdown functions */
  101. for(fp = Shutdown;*fp != NULL;fp++){
  102. (**fp)();
  103. }
  104. fcloseall();
  105. setirq(KBIRQ,Kbvec); /* Restore original keyboard vec */
  106. }
  107. /* Spawn subshell */
  108. int
  109. doshell(argc,argv,p)
  110. int argc;
  111. char *argv[];
  112. void *p;
  113. {
  114. char *command;
  115. int ret;
  116. if((command = getenv("COMSPEC")) == NULL)
  117. command = "/COMMAND.COM";
  118. ret = spawnv(P_WAIT,command,argv);
  119. return ret;
  120. }
  121. /* Read characters from the keyboard, translating them to "real" ASCII.
  122.  * If none are ready, block. The special keys are translated to values
  123.  * above 256, e.g., F-10 is 256 + 68 = 324.
  124.  */
  125. int
  126. kbread()
  127. {
  128. uint16 c;
  129. while((c = kbraw()) == 0)
  130. kwait(&Kbvec);
  131. rtype(c); /* Randomize random number state */
  132. /* Convert "extended ascii" to something more standard */
  133. if((c & 0xff) != 0)
  134. return c & 0xff;
  135. c >>= 8;
  136. switch(c){
  137. case 3: /* NULL (bizzare!) */
  138. c = 0;
  139. break;
  140. case 83: /* DEL key */
  141. c = DEL;
  142. break;
  143. default: /* Special key */
  144. c += 256;
  145. }
  146. return c;
  147. }
  148. /* Install hardware interrupt handler.
  149.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  150.  * Note that bus line IRQ2 maps to IRQ9 on the AT
  151.  */
  152. int
  153. setirq(irq,handler)
  154. unsigned irq;
  155. INTERRUPT (*handler)();
  156. {
  157. /* Set interrupt vector */
  158. if(irq < 8){
  159. setvect(8+irq,handler);
  160. } else if(irq < 16){
  161. Isat = 1;
  162. setvect(0x70 + irq - 8,handler);
  163. } else {
  164. return -1;
  165. }
  166. return 0;
  167. }
  168. /* Return pointer to hardware interrupt handler.
  169.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  170.  */
  171. INTERRUPT
  172. (*getirq(irq))()
  173. unsigned int irq;
  174. {
  175. /* Set interrupt vector */
  176. if(irq < 8){
  177. return getvect(8+irq);
  178. } else if(irq < 16){
  179. return getvect(0x70 + irq - 8);
  180. } else {
  181. return NULL;
  182. }
  183. }
  184. /* Disable hardware interrupt */
  185. int
  186. maskoff(irq)
  187. unsigned irq;
  188. {
  189. if(irq < 8){
  190. setbit(0x21,(char)(1<<irq));
  191. } else if(irq < 16){
  192. irq -= 8;
  193. setbit(0xa1,(char)(1<<irq));
  194. } else {
  195. return -1;
  196. }
  197. return 0;
  198. }
  199. /* Enable hardware interrupt */
  200. int
  201. maskon(irq)
  202. unsigned irq;
  203.  {
  204. if(irq < 8){
  205. clrbit(0x21,(char)(1<<irq));
  206. } else if(irq < 16){
  207. irq -= 8;
  208. clrbit(0xa1,(char)(1<<irq));
  209. } else {
  210. return -1;
  211. }
  212. return 0;
  213. }
  214. /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
  215. int
  216. getmask(irq)
  217. unsigned irq;
  218. {
  219. if(irq < 8)
  220. return (inportb(0x21) & (1 << irq)) ? 0 : 1;
  221. else if(irq < 16){
  222. irq -= 8;
  223. return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
  224. } else
  225. return -1;
  226. }
  227. /* Called from assembler stub linked to BIOS interrupt 1C, called on each
  228.  * hardware clock tick. Signal a clock tick to the timer process.
  229.  */
  230. void
  231. ctick()
  232. {
  233. Tick++;
  234. Clock++;
  235. ksignal(&Tick,1);
  236. }
  237. /* Read the Clock global variable, with interrupts off to avoid possible
  238.  * inconsistency on 16-bit machines
  239.  */
  240. int32
  241. rdclock()
  242. {
  243. int i_state;
  244. int32 rval;
  245. i_state = dirps();
  246. rval = Clock;
  247. restore(i_state);
  248. return rval;
  249. }
  250. /* Called from the timer process on every tick. NOTE! This function
  251.  * can NOT be called at interrupt time because it calls the BIOS
  252.  */
  253. void
  254. pctick()
  255. {
  256. long t;
  257. static long oldt; /* Value of bioscnt() on last call */
  258. /* Check for day change */
  259. t = bioscnt();
  260. if(t < oldt){
  261. /* Call the regular DOS time func to handle the midnight flag */
  262. (void)time(NULL);
  263. }
  264. }
  265. /* Set bit(s) in I/O port */
  266. void
  267. setbit(port,bits)
  268. unsigned port;
  269. char bits;
  270. {
  271. outportb(port,inportb(port)|bits);
  272. }
  273. /* Clear bit(s) in I/O port */
  274. void
  275. clrbit(port,bits)
  276. unsigned port;
  277. char bits;
  278. {
  279. outportb(port,inportb(port) & ~bits);
  280. }
  281. /* Set or clear selected bits(s) in I/O port */
  282. void
  283. writebit(port,mask,val)
  284. unsigned port;
  285. char mask;
  286. int val;
  287. {
  288. register char x;
  289. x = inportb(port);
  290. if(val)
  291. x |= mask;
  292. else
  293. x &= ~mask;
  294. outportb(port,x);
  295. }
  296. void *
  297. ltop(l)
  298. long l;
  299. {
  300. register unsigned seg,offset;
  301. seg = l >> 16;
  302. offset = l;
  303. return MK_FP(seg,offset);
  304. }
  305. #ifdef notdef /* Assembler versions in pcgen.asm */
  306. /* Multiply a 16-bit multiplier by an arbitrary length multiplicand.
  307.  * Product is left in place of the multiplicand, and the carry is
  308.  * returned
  309.  */
  310. uint16
  311. longmul(multiplier,n,multiplicand)
  312. uint16 multiplier;
  313. int n; /* Number of words in multiplicand[] */
  314. register uint16 *multiplicand; /* High word is in multiplicand[0] */
  315. {
  316. register int i;
  317. unsigned long pc;
  318. uint16 carry;
  319. carry = 0;
  320. multiplicand += n;
  321. for(i=n;i != 0;i--){
  322. multiplicand--;
  323. pc = carry + (unsigned long)multiplier * *multiplicand;
  324. *multiplicand = pc;
  325. carry = pc >> 16;
  326. }
  327. return carry;
  328. }
  329. /* Divide a 16-bit divisor into an arbitrary length dividend using
  330.  * long division. The quotient is returned in place of the dividend,
  331.  * and the function returns the remainder.
  332.  */
  333. uint16
  334. longdiv(divisor,n,dividend)
  335. uint16 divisor;
  336. int n; /* Number of words in dividend[] */
  337. register uint16 *dividend; /* High word is in dividend[0] */
  338. {
  339. /* Before each division, remquot contains the 32-bit dividend for this
  340.  * step, consisting of the 16-bit remainder from the previous division
  341.  * in the high word plus the current 16-bit dividend word in the low
  342.  * word.
  343.  *
  344.  * Immediately after the division, remquot contains the quotient
  345.  * in the low word and the remainder in the high word (which is
  346.  * exactly where we need it for the next division).
  347.  */
  348. unsigned long remquot;
  349. register int i;
  350. if(divisor == 0)
  351. return 0; /* Avoid divide-by-zero crash */
  352. remquot = 0;
  353. for(i=0;i<n;i++,dividend++){
  354. remquot |= *dividend;
  355. if(remquot == 0)
  356. continue; /* Avoid unnecessary division */
  357. #ifdef __TURBOC__
  358. /* Use assembly lang routine that returns both quotient
  359.  * and remainder, avoiding a second costly division
  360.  */
  361. remquot = divrem(remquot,divisor);
  362. *dividend = remquot; /* Extract quotient in low word */
  363. remquot &= ~0xffffL; /* ... and mask it off */
  364. #else
  365. *dividend = remquot / divisor;
  366. remquot = (remquot % divisor) << 16;
  367. #endif
  368. }
  369. return remquot >> 16;
  370. }
  371. #endif
  372. void
  373. sysreset()
  374. {
  375. void (*foo)(void);
  376. foo = MK_FP(0xffff,0); /* FFFF:0000 is hardware reset vector */
  377. (*foo)();
  378. }
  379. void
  380. display(i,v1,v2)
  381. int i;
  382. void *v1;
  383. void *v2;
  384. {
  385. struct session *sp;
  386. struct display *dp;
  387. static struct display *lastdp;
  388. static long lastkdebug;
  389. for(;;){
  390. sp = Current;
  391. if(sp == NULL || sp->output == NULL
  392.  || (dp = (struct display *)sp->output->ptr) == NULL){
  393. /* Something weird happened */
  394. ppause(500L);
  395. continue;
  396. }
  397. if(dp != lastdp || Kdebug != lastkdebug)
  398. dp->flags.dirty_screen = 1;
  399. statline(dp,sp);
  400. dupdate(dp);
  401. lastdp = dp;
  402. lastkdebug = Kdebug;
  403. kalarm(100L); /* Poll status every 100 ms */
  404. kwait(dp);
  405. kalarm(0L);
  406. }
  407. }
  408. /* Compose status line for bottom of screen
  409.  * Return 1 if session has unacked data and status should be polled,
  410.  * 0 otherwise.
  411.  *
  412.  */
  413. static void
  414. statline(dp,sp)
  415. struct display *dp;
  416. struct session *sp;
  417. {
  418. int attr;
  419. char buf[81];
  420. struct text_info text_info;
  421. int unack;
  422. int s1;
  423. int s = -1;
  424. /* Determine attribute to use */
  425. gettextinfo(&text_info);
  426. if(text_info.currmode == MONO)
  427. attr = 0x07; /* Regular white on black */
  428. else
  429. attr = 0x02; /* Green on black */
  430. if(sp->network != NULL && (s = fileno(sp->network)) != -1){
  431. unack = socklen(s,1);
  432. if(sp->type == FTP && (s1 = fileno(sp->cb.ftp->data)) != -1)
  433. unack += socklen(s1,1);
  434. }
  435. sprintf(buf,"%2d: %s",sp->index,sp->name);
  436. statwrite(dp,0,buf,strlen(buf),attr);
  437. if(dp->flags.scrollbk){
  438. sprintf(buf,"Scroll:%-5lu",dp->sfoffs);
  439. } else if(s != -1 && unack != 0){
  440. sprintf(buf,"Unack: %-5u",unack);
  441. } else
  442. sprintf(buf,"            ");
  443. statwrite(dp,54,buf,strlen(buf),attr);
  444. sprintf(buf,"F8:nxt F10:cmd");
  445. statwrite(dp,66,buf,strlen(buf),attr);
  446. }
  447. /* Return time since startup in milliseconds. If the system has an
  448.  * 8254 clock chip (standard on ATs and up) then resolution is improved
  449.  * below 55 ms (the clock tick interval) by reading back the instantaneous
  450.  * value of the counter and combining it with the global clock tick counter.
  451.  * Otherwise 55 ms resolution is provided.
  452.  *
  453.  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
  454.  * between the two reads. The tick counter is examined before and after the
  455.  * hardware counter is read. If the tick counter changes, try again.
  456.  * Note: the hardware counter counts down from 65536.
  457.  */
  458. int32
  459. msclock()
  460. {
  461. int32 hi;
  462. uint16 lo;
  463. uint16 count[4]; /* extended (48-bit) counter of timer clocks */
  464. if(!Isat)
  465. return rdclock() * MSPTICK;
  466. do {
  467. hi = rdclock();
  468. lo = clockbits();
  469. } while(hi != rdclock());
  470. count[0] = 0;
  471. count[1] = hi >> 16;
  472. count[2] = hi;
  473. count[3] = -lo;
  474. longmul(11,4,count); /* The ratio 11/13125 is exact */
  475. longdiv(13125,4,count);
  476. return ((long)count[2] << 16) + count[3];
  477. }
  478. /* Return clock in seconds */
  479. int32
  480. secclock()
  481. {
  482. int32 hi;
  483. uint16 lo;
  484. uint16 count[4]; /* extended (48-bit) counter of timer clocks */
  485. if(!Isat)
  486. return (rdclock() * MSPTICK) / 1000L;
  487. do {
  488. hi = rdclock();
  489. lo = clockbits();
  490. } while(hi != rdclock());
  491. count[0] = 0;
  492. count[1] = hi >> 16;
  493. count[2] = hi;
  494. count[3] = -lo;
  495. longmul(11,4,count); /* The ratio 11/13125 is exact */
  496. longdiv(13125,4,count);
  497. longdiv(1000,4,count); /* Convert to seconds */
  498. return ((long)count[2] << 16) + count[3];
  499. }
  500. /* Return time in raw clock counts, approx 838 ns */
  501. int32
  502. usclock()
  503. {
  504. int32 hi;
  505. uint16 lo;
  506. do {
  507. hi = rdclock();
  508. lo = clockbits();
  509. } while(hi != rdclock());
  510. return (hi << 16) - (int32)lo;
  511. }
  512. #if !defined(CPU386) /* 386s and above always have an AT bus */
  513. int
  514. doisat(argc,argv,p)
  515. int argc;
  516. char *argv[];
  517. void *p;
  518. {
  519. return setbool(&Isat,"AT/386 mode",argc,argv);
  520. }
  521. #endif
  522. /* Directly read BIOS count of time ticks. This is used instead of
  523.  * calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
  524.  * which resets the midnight overflow flag, losing days on the clock.
  525.  */
  526. long
  527. bioscnt()
  528. {
  529. long rval;
  530. int i_state;
  531. i_state = dirps();
  532. rval = * (long far *)MK_FP(0x40,0x6c);
  533. restore(i_state);
  534. return rval;
  535. }
  536. /* Null stub to replace Borland C++ library function called at startup time
  537.  * to setup the stdin/stdout/stderr streams
  538.  */
  539. void
  540. _setupio()
  541. {
  542. }
  543. /* Return 1 if running in interrupt context, 0 otherwise. Works by seeing if
  544.  * the stack pointer is inside the interrupt stack
  545.  */
  546. int
  547. intcontext()
  548. {
  549. if(_SS == FP_SEG(Intstk)
  550.  && _SP >= FP_OFF(Intstk) && _SP <= FP_OFF(Stktop))
  551. return 1;
  552. return 0;
  553. }
  554. /* Atomic read-and-decrement operation.
  555.  * Read the variable pointed to by p. If it is
  556.  * non-zero, decrement it. Return the original value.
  557.  */
  558. int
  559. arddec(p)
  560. volatile int *p;
  561. {
  562. int tmp;
  563. int i_state;
  564. i_state = dirps();
  565. tmp = *p;
  566. if(tmp != 0)
  567. (*p)--;
  568. restore(i_state);
  569. return tmp;
  570. }