BOOK.TXT
上传用户:jnzhq888
上传日期:2007-01-18
资源大小:51694k
文件大小:1020k
源码类别:

操作系统开发

开发平台:

WINDOWS

  1. 07895 /* Build descriptor for a code segment. */
  2. 07896
  3. 07897   sdesc(segdp, base, size);
  4. 07898   segdp->access = (privilege << DPL_SHIFT)
  5. 07899                 | (PRESENT | SEGMENT | EXECUTABLE | READABLE);
  6. 07900                 /* CONFORMING = 0, ACCESSED = 0 */
  7. 07901 }
  8. 07903 /*=========================================================================*
  9. 07904  *                              init_dataseg                               *
  10. 07905  *=========================================================================*/
  11. 07906 PUBLIC void init_dataseg(segdp, base, size, privilege)
  12. 07907 register struct segdesc_s *segdp;
  13. 07908 phys_bytes base;
  14. 07909 phys_bytes size;
  15. 07910 int privilege;
  16. 07911 {
  17. 07912 /* Build descriptor for a data segment. */
  18. 07913
  19. 07914   sdesc(segdp, base, size);
  20. 07915   segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT | WRITEABLE);
  21. 07916                 /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
  22. 07917 }
  23. 07919 /*=========================================================================*
  24. 07920  *                              sdesc                                      *
  25. 07921  *=========================================================================*/
  26. 07922 PRIVATE void sdesc(segdp, base, size)
  27. 07923 register struct segdesc_s *segdp;
  28. 07924 phys_bytes base;
  29. 07925 phys_bytes size;
  30. 07926 {
  31. 07927 /* Fill in the size fields (base, limit and granularity) of a descriptor. */
  32. 07928
  33. 07929   segdp->base_low = base;
  34. 07930   segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
  35. 07931   segdp->base_high = base >> BASE_HIGH_SHIFT;
  36. 07932   --size;                       /* convert to a limit, 0 size means 4G */
  37. 07933   if (size > BYTE_GRAN_MAX) {
  38. 07934         segdp->limit_low = size >> PAGE_GRAN_SHIFT;
  39. 07935         segdp->granularity = GRANULAR | (size >>
  40. 07936                                      (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
  41. 07937   } else {
  42. 07938         segdp->limit_low = size;
  43. 07939         segdp->granularity = size >> GRANULARITY_SHIFT;
  44. 07940   }
  45. 07941   segdp->granularity |= DEFAULT;        /* means BIG for data seg */
  46. 07942 }
  47. 07944 /*=========================================================================*
  48. 07945  *                              seg2phys                                   *
  49. 07946  *=========================================================================*/
  50. 07947 PUBLIC phys_bytes seg2phys(seg)
  51. 07948 U16_t seg;
  52. 07949 {
  53. 07950 /* Return the base address of a segment, with seg being either a 8086 segment
  54. 07951  * register, or a 286/386 segment selector.
  55. 07952  */
  56. 07953   phys_bytes base;
  57. 07954   struct segdesc_s *segdp;
  58. 07955
  59. 07956   if (!protected_mode) {
  60. 07957         base = hclick_to_physb(seg);
  61. 07958   } else {
  62. 07959         segdp = &gdt[seg >> 3];
  63. 07960         base = segdp->base_low | ((u32_t) segdp->base_middle << 16);
  64. 07961         base |= ((u32_t) segdp->base_high << 24);
  65. 07962   }
  66. 07963   return base;
  67. 07964 }
  68. 07966 /*=========================================================================*
  69. 07967  *                              int_gate                                   *
  70. 07968  *=========================================================================*/
  71. 07969 PRIVATE void int_gate(vec_nr, base, dpl_type)
  72. 07970 unsigned vec_nr;
  73. 07971 phys_bytes base;
  74. 07972 unsigned dpl_type;
  75. 07973 {
  76. 07974 /* Build descriptor for an interrupt gate. */
  77. 07975
  78. 07976   register struct gatedesc_s *idp;
  79. 07977
  80. 07978   idp = &idt[vec_nr];
  81. 07979   idp->offset_low = base;
  82. 07980   idp->selector = CS_SELECTOR;
  83. 07981   idp->p_dpl_type = dpl_type;
  84. 07982   idp->offset_high = base >> OFFSET_HIGH_SHIFT;
  85. 07983 }
  86. 07985 /*=========================================================================*
  87. 07986  *                              enable_iop                                 *
  88. 07987  *=========================================================================*/
  89. 07988 PUBLIC void enable_iop(pp)
  90. 07989 struct proc *pp;
  91. 07990 {
  92. 07991 /* Allow a user process to use I/O instructions.  Change the I/O Permission
  93. 07992  * Level bits in the psw. These specify least-privileged Current Permission
  94. 07993  * Level allowed to execute I/O instructions. Users and servers have CPL 3. 
  95. 07994  * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
  96. 07995  */
  97. 07996   pp->p_reg.psw |= 0x3000;
  98. 07997 }
  99. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  100. src/kernel/klib.s    
  101. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  102. 08000 #
  103. 08001 ! Chooses between the 8086 and 386 versions of the low level kernel code.
  104. 08002
  105. 08003 #include <minix/config.h>
  106. 08004 #if _WORD_SIZE == 2
  107. 08005 #include "klib88.s"
  108. 08006 #else
  109. 08007 #include "klib386.s"
  110. 08008 #endif
  111. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  112. src/kernel/klib386.s    
  113. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  114. 08100 #
  115. 08101 ! sections
  116. 08102
  117. 08103 .sect .text; .sect .rom; .sect .data; .sect .bss
  118. 08104
  119. 08105 #include <minix/config.h>
  120. 08106 #include <minix/const.h>
  121. 08107 #include "const.h"
  122. 08108 #include "sconst.h"
  123. 08109 #include "protect.h"
  124. 08110
  125. 08111 ! This file contains a number of assembly code utility routines needed by the
  126. 08112 ! kernel.  They are:
  127. 08113
  128. 08114 .define _monitor        ! exit Minix and return to the monitor
  129. 08115 .define _check_mem      ! check a block of memory, return the valid size
  130. 08116 .define _cp_mess        ! copies messages from source to destination
  131. 08117 .define _exit           ! dummy for library routines
  132. 08118 .define __exit          ! dummy for library routines
  133. 08119 .define ___exit         ! dummy for library routines
  134. 08120 .define ___main         ! dummy for GCC
  135. 08121 .define _in_byte        ! read a byte from a port and return it
  136. 08122 .define _in_word        ! read a word from a port and return it
  137. 08123 .define _out_byte       ! write a byte to a port
  138. 08124 .define _out_word       ! write a word to a port
  139. 08125 .define _port_read      ! transfer data from (disk controller) port to memory
  140. 08126 .define _port_read_byte ! likewise byte by byte
  141. 08127 .define _port_write     ! transfer data from memory to (disk controller) port
  142. 08128 .define _port_write_byte ! likewise byte by byte
  143. 08129 .define _lock           ! disable interrupts
  144. 08130 .define _unlock         ! enable interrupts
  145. 08131 .define _enable_irq     ! enable an irq at the 8259 controller
  146. 08132 .define _disable_irq    ! disable an irq
  147. 08133 .define _phys_copy      ! copy data from anywhere to anywhere in memory
  148. 08134 .define _mem_rdw        ! copy one word from [segment:offset]
  149. 08135 .define _reset          ! reset the system
  150. 08136 .define _mem_vid_copy   ! copy data to video ram
  151. 08137 .define _vid_vid_copy   ! move data in video ram
  152. 08138 .define _level0         ! call a function at level 0
  153. 08139
  154. 08140 ! The routines only guarantee to preserve the registers the C compiler
  155. 08141 ! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
  156. 08142 ! direction bit in the flags).
  157. 08143
  158. 08144 ! imported variables
  159. 08145
  160. 08146 .sect .bss
  161. 08147 .extern _mon_return, _mon_sp
  162. 08148 .extern _irq_use
  163. 08149 .extern _blank_color
  164. 08150 .extern _ext_memsize
  165. 08151 .extern _gdt
  166. 08152 .extern _low_memsize
  167. 08153 .extern _sizes
  168. 08154 .extern _vid_seg
  169. 08155 .extern _vid_size
  170. 08156 .extern _vid_mask
  171. 08157 .extern _level0_func
  172. 08158
  173. 08159 .sect .text
  174. 08160 !*===========================================================================*
  175. 08161 !*                              monitor                                      *
  176. 08162 !*===========================================================================*
  177. 08163 ! PUBLIC void monitor();
  178. 08164 ! Return to the monitor.
  179. 08165
  180. 08166 _monitor:
  181. 08167         mov     eax, (_reboot_code)     ! address of new parameters
  182. 08168         mov     esp, (_mon_sp)          ! restore monitor stack pointer
  183. 08169     o16 mov     dx, SS_SELECTOR         ! monitor data segment
  184. 08170         mov     ds, dx
  185. 08171         mov     es, dx
  186. 08172         mov     fs, dx
  187. 08173         mov     gs, dx
  188. 08174         mov     ss, dx
  189. 08175         pop     edi
  190. 08176         pop     esi
  191. 08177         pop     ebp
  192. 08178     o16 retf                            ! return to the monitor
  193. 08179
  194. 08180
  195. 08181 !*===========================================================================*
  196. 08182 !*                              check_mem                                    *
  197. 08183 !*===========================================================================*
  198. 08184 ! PUBLIC phys_bytes check_mem(phys_bytes base, phys_bytes size);
  199. 08185 ! Check a block of memory, return the amount valid.
  200. 08186 ! Only every 16th byte is checked.
  201. 08187 ! An initial size of 0 means everything.
  202. 08188 ! This really should do some alias checks.
  203. 08189
  204. 08190 CM_DENSITY      =       16
  205. 08191 CM_LOG_DENSITY  =       4
  206. 08192 TEST1PATTERN    =       0x55            ! memory test pattern 1
  207. 08193 TEST2PATTERN    =       0xAA            ! memory test pattern 2
  208. 08194
  209. 08195 CHKM_ARGS       =       4 + 4 + 4       ! 4 + 4
  210. 08196 !                       ds ebx eip      base size
  211. 08197
  212. 08198 _check_mem:
  213. 08199         push    ebx
  214. 08200         push    ds
  215. 08201     o16 mov     ax, FLAT_DS_SELECTOR
  216. 08202         mov     ds, ax
  217. 08203         mov     eax, CHKM_ARGS(esp)
  218. 08204         mov     ebx, eax
  219. 08205         mov     ecx, CHKM_ARGS+4(esp)
  220. 08206         shr     ecx, CM_LOG_DENSITY
  221. 08207 cm_loop:
  222. 08208         movb    dl, TEST1PATTERN
  223. 08209         xchgb   dl, (eax)               ! write test pattern, remember original
  224. 08210         xchgb   dl, (eax)               ! restore original, read test pattern
  225. 08211         cmpb    dl, TEST1PATTERN        ! must agree if good real memory
  226. 08212         jnz     cm_exit                 ! if different, memory is unusable
  227. 08213         movb    dl, TEST2PATTERN
  228. 08214         xchgb   dl, (eax)
  229. 08215         xchgb   dl, (eax)
  230. 08216         add     eax, CM_DENSITY
  231. 08217         cmpb    dl, TEST2PATTERN
  232. 08218         loopz   cm_loop
  233. 08219 cm_exit:
  234. 08220         sub     eax, ebx
  235. 08221         pop     ds
  236. 08222         pop     ebx
  237. 08223         ret
  238. 08224
  239. 08225
  240. 08226 !*===========================================================================*
  241. 08227 !*                              cp_mess                                      *
  242. 08228 !*===========================================================================*
  243. 08229 ! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset,
  244. 08230 !                     phys_clicks dst_clicks, vir_bytes dst_offset);
  245. 08231 ! This routine makes a fast copy of a message from anywhere in the address
  246. 08232 ! space to anywhere else.  It also copies the source address provided as a
  247. 08233 ! parameter to the call into the first word of the destination message.
  248. 08234 !
  249. 08235 ! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set
  250. 08236 ! correctly.  Changing the definition of message in the type file and not
  251. 08237 ! changing it here will lead to total disaster.
  252. 08238
  253. 08239 CM_ARGS =       4 + 4 + 4 + 4 + 4       ! 4 + 4 + 4 + 4 + 4
  254. 08240 !               es  ds edi esi eip      proc scl sof dcl dof
  255. 08241
  256. 08242         .align  16
  257. 08243 _cp_mess:
  258. 08244         cld
  259. 08245         push    esi
  260. 08246         push    edi
  261. 08247         push    ds
  262. 08248         push    es
  263. 08249
  264. 08250         mov     eax, FLAT_DS_SELECTOR
  265. 08251         mov     ds, ax
  266. 08252         mov     es, ax
  267. 08253
  268. 08254         mov     esi, CM_ARGS+4(esp)             ! src clicks
  269. 08255         shl     esi, CLICK_SHIFT
  270. 08256         add     esi, CM_ARGS+4+4(esp)           ! src offset
  271. 08257         mov     edi, CM_ARGS+4+4+4(esp)         ! dst clicks
  272. 08258         shl     edi, CLICK_SHIFT
  273. 08259         add     edi, CM_ARGS+4+4+4+4(esp)       ! dst offset
  274. 08260
  275. 08261         mov     eax, CM_ARGS(esp)       ! process number of sender
  276. 08262         stos                            ! copy number of sender to dest message
  277. 08263         add     esi, 4                  ! do not copy first word
  278. 08264         mov     ecx, Msize - 1          ! remember, first word does not count
  279. 08265         rep
  280. 08266         movs                            ! copy the message
  281. 08267
  282. 08268         pop     es
  283. 08269         pop     ds
  284. 08270         pop     edi
  285. 08271         pop     esi
  286. 08272         ret                             ! that is all folks!
  287. 08273
  288. 08274
  289. 08275 !*===========================================================================*
  290. 08276 !*                              exit                                         *
  291. 08277 !*===========================================================================*
  292. 08278 ! PUBLIC void exit();
  293. 08279 ! Some library routines use exit, so provide a dummy version.
  294. 08280 ! Actual calls to exit cannot occur in the kernel.
  295. 08281 ! GNU CC likes to call ___main from main() for nonobvious reasons.
  296. 08282
  297. 08283 _exit:
  298. 08284 __exit:
  299. 08285 ___exit:
  300. 08286         sti
  301. 08287         jmp     ___exit
  302. 08288
  303. 08289 ___main:
  304. 08290         ret
  305. 08291
  306. 08292
  307. 08293 !*===========================================================================*
  308. 08294 !*                              in_byte                                      *
  309. 08295 !*===========================================================================*
  310. 08296 ! PUBLIC unsigned in_byte(port_t port);
  311. 08297 ! Read an (unsigned) byte from the i/o port  port  and return it.
  312. 08298
  313. 08299         .align  16
  314. 08300 _in_byte:
  315. 08301         mov     edx, 4(esp)             ! port
  316. 08302         sub     eax, eax
  317. 08303         inb     dx                      ! read 1 byte
  318. 08304         ret
  319. 08305
  320. 08306
  321. 08307 !*===========================================================================*
  322. 08308 !*                              in_word                                      *
  323. 08309 !*===========================================================================*
  324. 08310 ! PUBLIC unsigned in_word(port_t port);
  325. 08311 ! Read an (unsigned) word from the i/o port  port  and return it.
  326. 08312
  327. 08313         .align  16
  328. 08314 _in_word:
  329. 08315         mov     edx, 4(esp)             ! port
  330. 08316         sub     eax, eax
  331. 08317     o16 in      dx                      ! read 1 word
  332. 08318         ret
  333. 08319
  334. 08320
  335. 08321 !*===========================================================================*
  336. 08322 !*                              out_byte                                     *
  337. 08323 !*===========================================================================*
  338. 08324 ! PUBLIC void out_byte(port_t port, u8_t value);
  339. 08325 ! Write  value  (cast to a byte)  to the I/O port  port.
  340. 08326
  341. 08327         .align  16
  342. 08328 _out_byte:
  343. 08329         mov     edx, 4(esp)             ! port
  344. 08330         movb    al, 4+4(esp)            ! value
  345. 08331         outb    dx                      ! output 1 byte
  346. 08332         ret
  347. 08333
  348. 08334
  349. 08335 !*===========================================================================*
  350. 08336 !*                              out_word                                     *
  351. 08337 !*===========================================================================*
  352. 08338 ! PUBLIC void out_word(Port_t port, U16_t value);
  353. 08339 ! Write  value  (cast to a word)  to the I/O port  port.
  354. 08340
  355. 08341         .align  16
  356. 08342 _out_word:
  357. 08343         mov     edx, 4(esp)             ! port
  358. 08344         mov     eax, 4+4(esp)           ! value
  359. 08345     o16 out     dx                      ! output 1 word
  360. 08346         ret
  361. 08347
  362. 08348
  363. 08349 !*===========================================================================*
  364. 08350 !*                              port_read                                    *
  365. 08351 !*===========================================================================*
  366. 08352 ! PUBLIC void port_read(port_t port, phys_bytes destination, unsigned bytcount);
  367. 08353 ! Transfer data from (hard disk controller) port to memory.
  368. 08354
  369. 08355 PR_ARGS =       4 + 4 + 4               ! 4 + 4 + 4
  370. 08356 !               es edi eip              port dst len
  371. 08357
  372. 08358         .align  16
  373. 08359 _port_read:
  374. 08360         cld
  375. 08361         push    edi
  376. 08362         push    es
  377. 08363         mov     ecx, FLAT_DS_SELECTOR
  378. 08364         mov     es, cx
  379. 08365         mov     edx, PR_ARGS(esp)       ! port to read from
  380. 08366         mov     edi, PR_ARGS+4(esp)     ! destination addr
  381. 08367         mov     ecx, PR_ARGS+4+4(esp)   ! byte count
  382. 08368         shr     ecx, 1                  ! word count
  383. 08369         rep                             ! (hardware cannot handle dwords)
  384. 08370     o16 ins                             ! read everything
  385. 08371         pop     es
  386. 08372         pop     edi
  387. 08373         ret
  388. 08374
  389. 08375
  390. 08376 !*===========================================================================*
  391. 08377 !*                              port_read_byte                               *
  392. 08378 !*===========================================================================*
  393. 08379 ! PUBLIC void port_read_byte(port_t port, phys_bytes destination,
  394. 08380 !                                               unsigned bytcount);
  395. 08381 ! Transfer data from port to memory.
  396. 08382
  397. 08383 PR_ARGS_B =     4 + 4 + 4               ! 4 + 4 + 4
  398. 08384 !               es edi eip              port dst len
  399. 08385
  400. 08386 _port_read_byte:
  401. 08387         cld
  402. 08388         push    edi
  403. 08389         push    es
  404. 08390         mov     ecx, FLAT_DS_SELECTOR
  405. 08391         mov     es, cx
  406. 08392         mov     edx, PR_ARGS_B(esp)
  407. 08393         mov     edi, PR_ARGS_B+4(esp)
  408. 08394         mov     ecx, PR_ARGS_B+4+4(esp)
  409. 08395         rep
  410. 08396         insb
  411. 08397         pop     es
  412. 08398         pop     edi
  413. 08399         ret
  414. 08400
  415. 08401
  416. 08402 !*===========================================================================*
  417. 08403 !*                              port_write                                   *
  418. 08404 !*===========================================================================*
  419. 08405 ! PUBLIC void port_write(port_t port, phys_bytes source, unsigned bytcount);
  420. 08406 ! Transfer data from memory to (hard disk controller) port.
  421. 08407
  422. 08408 PW_ARGS =       4 + 4 + 4               ! 4 + 4 + 4
  423. 08409 !               es edi eip              port src len
  424. 08410
  425. 08411         .align  16
  426. 08412 _port_write:
  427. 08413         cld
  428. 08414         push    esi
  429. 08415         push    ds
  430. 08416         mov     ecx, FLAT_DS_SELECTOR
  431. 08417         mov     ds, cx
  432. 08418         mov     edx, PW_ARGS(esp)       ! port to write to
  433. 08419         mov     esi, PW_ARGS+4(esp)     ! source addr
  434. 08420         mov     ecx, PW_ARGS+4+4(esp)   ! byte count
  435. 08421         shr     ecx, 1                  ! word count
  436. 08422         rep                             ! (hardware cannot handle dwords)
  437. 08423     o16 outs                            ! write everything
  438. 08424         pop     ds
  439. 08425         pop     esi
  440. 08426         ret
  441. 08427
  442. 08428
  443. 08429 !*===========================================================================*
  444. 08430 !*                              port_write_byte                              *
  445. 08431 !*===========================================================================*
  446. 08432 ! PUBLIC void port_write_byte(port_t port, phys_bytes source,
  447. 08433 !                                               unsigned bytcount);
  448. 08434 ! Transfer data from memory to port.
  449. 08435
  450. 08436 PW_ARGS_B =     4 + 4 + 4               ! 4 + 4 + 4
  451. 08437 !               es edi eip              port src len
  452. 08438
  453. 08439 _port_write_byte:
  454. 08440         cld
  455. 08441         push    esi
  456. 08442         push    ds
  457. 08443         mov     ecx, FLAT_DS_SELECTOR
  458. 08444         mov     ds, cx
  459. 08445         mov     edx, PW_ARGS_B(esp)
  460. 08446         mov     esi, PW_ARGS_B+4(esp)
  461. 08447         mov     ecx, PW_ARGS_B+4+4(esp)
  462. 08448         rep
  463. 08449         outsb
  464. 08450         pop     ds
  465. 08451         pop     esi
  466. 08452         ret
  467. 08453
  468. 08454
  469. 08455 !*===========================================================================*
  470. 08456 !*                              lock                                         *
  471. 08457 !*===========================================================================*
  472. 08458 ! PUBLIC void lock();
  473. 08459 ! Disable CPU interrupts.
  474. 08460
  475. 08461         .align  16
  476. 08462 _lock:
  477. 08463         cli                             ! disable interrupts
  478. 08464         ret
  479. 08465
  480. 08466
  481. 08467 !*===========================================================================*
  482. 08468 !*                              unlock                                       *
  483. 08469 !*===========================================================================*
  484. 08470 ! PUBLIC void unlock();
  485. 08471 ! Enable CPU interrupts.
  486. 08472
  487. 08473         .align  16
  488. 08474 _unlock:
  489. 08475         sti
  490. 08476         ret
  491. 08477
  492. 08478
  493. 08479 !*==========================================================================*
  494. 08480 !*                              enable_irq                                  *
  495. 08481 !*==========================================================================*/
  496. 08482 ! PUBLIC void enable_irq(unsigned irq)
  497. 08483 ! Enable an interrupt request line by clearing an 8259 bit.
  498. 08484 ! Equivalent code for irq < 8:
  499. 08485 !       out_byte(INT_CTLMASK, in_byte(INT_CTLMASK) & ~(1 << irq));
  500. 08486
  501. 08487         .align  16
  502. 08488 _enable_irq:
  503. 08489         mov     ecx, 4(esp)             ! irq
  504. 08490         pushf
  505. 08491         cli
  506. 08492         movb    ah, ~1
  507. 08493         rolb    ah, cl                  ! ah = ~(1 << (irq % 8))
  508. 08494         cmpb    cl, 8
  509. 08495         jae     enable_8                ! enable irq >= 8 at the slave 8259
  510. 08496 enable_0:
  511. 08497         inb     INT_CTLMASK
  512. 08498         andb    al, ah
  513. 08499         outb    INT_CTLMASK             ! clear bit at master 8259
  514. 08500         popf
  515. 08501         ret
  516. 08502         .align  4
  517. 08503 enable_8:
  518. 08504         inb     INT2_CTLMASK
  519. 08505         andb    al, ah
  520. 08506         outb    INT2_CTLMASK            ! clear bit at slave 8259
  521. 08507         popf
  522. 08508         ret
  523. 08509
  524. 08510
  525. 08511 !*==========================================================================*
  526. 08512 !*                              disable_irq                                 *
  527. 08513 !*==========================================================================*/
  528. 08514 ! PUBLIC int disable_irq(unsigned irq)
  529. 08515 ! Disable an interrupt request line by setting an 8259 bit.
  530. 08516 ! Equivalent code for irq < 8:
  531. 08517 !       out_byte(INT_CTLMASK, in_byte(INT_CTLMASK) | (1 << irq));
  532. 08518 ! Returns true iff the interrupt was not already disabled.
  533. 08519
  534. 08520         .align  16
  535. 08521 _disable_irq:
  536. 08522         mov     ecx, 4(esp)             ! irq
  537. 08523         pushf
  538. 08524         cli
  539. 08525         movb    ah, 1
  540. 08526         rolb    ah, cl                  ! ah = (1 << (irq % 8))
  541. 08527         cmpb    cl, 8
  542. 08528         jae     disable_8               ! disable irq >= 8 at the slave 8259
  543. 08529 disable_0:
  544. 08530         inb     INT_CTLMASK
  545. 08531         testb   al, ah
  546. 08532         jnz     dis_already             ! already disabled?
  547. 08533         orb     al, ah
  548. 08534         outb    INT_CTLMASK             ! set bit at master 8259
  549. 08535         popf
  550. 08536         mov     eax, 1                  ! disabled by this function
  551. 08537         ret
  552. 08538 disable_8:
  553. 08539         inb     INT2_CTLMASK
  554. 08540         testb   al, ah
  555. 08541         jnz     dis_already             ! already disabled?
  556. 08542         orb     al, ah
  557. 08543         outb    INT2_CTLMASK            ! set bit at slave 8259
  558. 08544         popf
  559. 08545         mov     eax, 1                  ! disabled by this function
  560. 08546         ret
  561. 08547 dis_already:
  562. 08548         popf
  563. 08549         xor     eax, eax                ! already disabled
  564. 08550         ret
  565. 08551
  566. 08552
  567. 08553 !*===========================================================================*
  568. 08554 !*                              phys_copy                                    *
  569. 08555 !*===========================================================================*
  570. 08556 ! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination,
  571. 08557 !                       phys_bytes bytecount);
  572. 08558 ! Copy a block of physical memory.
  573. 08559
  574. 08560 PC_ARGS =       4 + 4 + 4 + 4   ! 4 + 4 + 4
  575. 08561 !               es edi esi eip   src dst len
  576. 08562
  577. 08563         .align  16
  578. 08564 _phys_copy:
  579. 08565         cld
  580. 08566         push    esi
  581. 08567         push    edi
  582. 08568         push    es
  583. 08569
  584. 08570         mov     eax, FLAT_DS_SELECTOR
  585. 08571         mov     es, ax
  586. 08572
  587. 08573         mov     esi, PC_ARGS(esp)
  588. 08574         mov     edi, PC_ARGS+4(esp)
  589. 08575         mov     eax, PC_ARGS+4+4(esp)
  590. 08576
  591. 08577         cmp     eax, 10                 ! avoid align overhead for small counts
  592. 08578         jb      pc_small
  593. 08579         mov     ecx, esi                ! align source, hope target is too
  594. 08580         neg     ecx
  595. 08581         and     ecx, 3                  ! count for alignment
  596. 08582         sub     eax, ecx
  597. 08583         rep
  598. 08584    eseg movsb
  599. 08585         mov     ecx, eax
  600. 08586         shr     ecx, 2                  ! count of dwords
  601. 08587         rep
  602. 08588    eseg movs
  603. 08589         and     eax, 3
  604. 08590 pc_small:
  605. 08591         xchg    ecx, eax                ! remainder
  606. 08592         rep
  607. 08593    eseg movsb
  608. 08594
  609. 08595         pop     es
  610. 08596         pop     edi
  611. 08597         pop     esi
  612. 08598         ret
  613. 08599
  614. 08600
  615. 08601 !*===========================================================================*
  616. 08602 !*                              mem_rdw                                      *
  617. 08603 !*===========================================================================*
  618. 08604 ! PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
  619. 08605 ! Load and return word at far pointer segment:offset.
  620. 08606
  621. 08607         .align  16
  622. 08608 _mem_rdw:
  623. 08609         mov     cx, ds
  624. 08610         mov     ds, 4(esp)              ! segment
  625. 08611         mov     eax, 4+4(esp)           ! offset
  626. 08612         movzx   eax, (eax)              ! word to return
  627. 08613         mov     ds, cx
  628. 08614         ret
  629. 08615
  630. 08616
  631. 08617 !*===========================================================================*
  632. 08618 !*                              reset                                        *
  633. 08619 !*===========================================================================*
  634. 08620 ! PUBLIC void reset();
  635. 08621 ! Reset the system by loading IDT with offset 0 and interrupting.
  636. 08622
  637. 08623 _reset:
  638. 08624         lidt    (idt_zero)
  639. 08625         int     3               ! anything goes, the 386 will not like it
  640. 08626 .sect .data
  641. 08627 idt_zero:       .data4  0, 0
  642. 08628 .sect .text
  643. 08629
  644. 08630
  645. 08631 !*===========================================================================*
  646. 08632 !*                              mem_vid_copy                                 *
  647. 08633 !*===========================================================================*
  648. 08634 ! PUBLIC void mem_vid_copy(u16 *src, unsigned dst, unsigned count);
  649. 08635 !
  650. 08636 ! Copy count characters from kernel memory to video memory.  Src, dst and
  651. 08637 ! count are character (word) based video offsets and counts.  If src is null
  652. 08638 ! then screen memory is blanked by filling it with blank_color.
  653. 08639
  654. 08640 MVC_ARGS        =       4 + 4 + 4 + 4   ! 4 + 4 + 4
  655. 08641 !                       es edi esi eip   src dst ct
  656. 08642
  657. 08643 _mem_vid_copy:
  658. 08644         push    esi
  659. 08645         push    edi
  660. 08646         push    es
  661. 08647         mov     esi, MVC_ARGS(esp)      ! source
  662. 08648         mov     edi, MVC_ARGS+4(esp)    ! destination
  663. 08649         mov     edx, MVC_ARGS+4+4(esp)  ! count
  664. 08650         mov     es, (_vid_seg)          ! destination is video segment
  665. 08651         cld                             ! make sure direction is up
  666. 08652 mvc_loop:
  667. 08653         and     edi, (_vid_mask)        ! wrap address
  668. 08654         mov     ecx, edx                ! one chunk to copy
  669. 08655         mov     eax, (_vid_size)
  670. 08656         sub     eax, edi
  671. 08657         cmp     ecx, eax
  672. 08658         jbe     0f
  673. 08659         mov     ecx, eax                ! ecx = min(ecx, vid_size - edi)
  674. 08660 0:      sub     edx, ecx                ! count -= ecx
  675. 08661         shl     edi, 1                  ! byte address
  676. 08662         test    esi, esi                ! source == 0 means blank the screen
  677. 08663         jz      mvc_blank
  678. 08664 mvc_copy:
  679. 08665         rep                             ! copy words to video memory
  680. 08666     o16 movs
  681. 08667         jmp     mvc_test
  682. 08668 mvc_blank:
  683. 08669         mov     eax, (_blank_color)     ! ax = blanking character
  684. 08670         rep
  685. 08671     o16 stos                            ! copy blanks to video memory
  686. 08672         !jmp    mvc_test
  687. 08673 mvc_test:
  688. 08674         shr     edi, 1                  ! word addresses
  689. 08675         test    edx, edx
  690. 08676         jnz     mvc_loop
  691. 08677 mvc_done:
  692. 08678         pop     es
  693. 08679         pop     edi
  694. 08680         pop     esi
  695. 08681         ret
  696. 08682
  697. 08683
  698. 08684 !*===========================================================================*
  699. 08685 !*                              vid_vid_copy                                 *
  700. 08686 !*===========================================================================*
  701. 08687 ! PUBLIC void vid_vid_copy(unsigned src, unsigned dst, unsigned count);
  702. 08688 !
  703. 08689 ! Copy count characters from video memory to video memory.  Handle overlap.
  704. 08690 ! Used for scrolling, line or character insertion and deletion.  Src, dst
  705. 08691 ! and count are character (word) based video offsets and counts.
  706. 08692
  707. 08693 VVC_ARGS        =       4 + 4 + 4 + 4   ! 4 + 4 + 4
  708. 08694 !                       es edi esi eip   src dst ct
  709. 08695
  710. 08696 _vid_vid_copy:
  711. 08697         push    esi
  712. 08698         push    edi
  713. 08699         push    es
  714. 08700         mov     esi, VVC_ARGS(esp)      ! source
  715. 08701         mov     edi, VVC_ARGS+4(esp)    ! destination
  716. 08702         mov     edx, VVC_ARGS+4+4(esp)  ! count
  717. 08703         mov     es, (_vid_seg)          ! use video segment
  718. 08704         cmp     esi, edi                ! copy up or down?
  719. 08705         jb      vvc_down
  720. 08706 vvc_up:
  721. 08707         cld                             ! direction is up
  722. 08708 vvc_uploop:
  723. 08709         and     esi, (_vid_mask)        ! wrap addresses
  724. 08710         and     edi, (_vid_mask)
  725. 08711         mov     ecx, edx                ! one chunk to copy
  726. 08712         mov     eax, (_vid_size)
  727. 08713         sub     eax, esi
  728. 08714         cmp     ecx, eax
  729. 08715         jbe     0f
  730. 08716         mov     ecx, eax                ! ecx = min(ecx, vid_size - esi)
  731. 08717 0:      mov     eax, (_vid_size)
  732. 08718         sub     eax, edi
  733. 08719         cmp     ecx, eax
  734. 08720         jbe     0f
  735. 08721         mov     ecx, eax                ! ecx = min(ecx, vid_size - edi)
  736. 08722 0:      sub     edx, ecx                ! count -= ecx
  737. 08723         shl     esi, 1
  738. 08724         shl     edi, 1                  ! byte addresses
  739. 08725         rep
  740. 08726 eseg o16 movs                           ! copy video words
  741. 08727         shr     esi, 1
  742. 08728         shr     edi, 1                  ! word addresses
  743. 08729         test    edx, edx
  744. 08730         jnz     vvc_uploop              ! again?
  745. 08731         jmp     vvc_done
  746. 08732 vvc_down:
  747. 08733         std                             ! direction is down
  748. 08734         lea     esi, -1(esi)(edx*1)     ! start copying at the top
  749. 08735         lea     edi, -1(edi)(edx*1)
  750. 08736 vvc_downloop:
  751. 08737         and     esi, (_vid_mask)        ! wrap addresses
  752. 08738         and     edi, (_vid_mask)
  753. 08739         mov     ecx, edx                ! one chunk to copy
  754. 08740         lea     eax, 1(esi)
  755. 08741         cmp     ecx, eax
  756. 08742         jbe     0f
  757. 08743         mov     ecx, eax                ! ecx = min(ecx, esi + 1)
  758. 08744 0:      lea     eax, 1(edi)
  759. 08745         cmp     ecx, eax
  760. 08746         jbe     0f
  761. 08747         mov     ecx, eax                ! ecx = min(ecx, edi + 1)
  762. 08748 0:      sub     edx, ecx                ! count -= ecx
  763. 08749         shl     esi, 1
  764. 08750         shl     edi, 1                  ! byte addresses
  765. 08751         rep
  766. 08752 eseg o16 movs                           ! copy video words
  767. 08753         shr     esi, 1
  768. 08754         shr     edi, 1                  ! word addresses
  769. 08755         test    edx, edx
  770. 08756         jnz     vvc_downloop            ! again?
  771. 08757         cld                             ! C compiler expect up
  772. 08758         !jmp    vvc_done
  773. 08759 vvc_done:
  774. 08760         pop     es
  775. 08761         pop     edi
  776. 08762         pop     esi
  777. 08763         ret
  778. 08764
  779. 08765
  780. 08766 !*===========================================================================*
  781. 08767 !*                            level0                                         *
  782. 08768 !*===========================================================================*
  783. 08769 ! PUBLIC void level0(void (*func)(void))
  784. 08770 ! Call a function at permission level 0.  This allows kernel tasks to do
  785. 08771 ! things that are only possible at the most privileged CPU level.
  786. 08772 !
  787. 08773 _level0:
  788. 08774         mov     eax, 4(esp)
  789. 08775         mov     (_level0_func), eax
  790. 08776         int     LEVEL0_VECTOR
  791. 08777         ret
  792. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  793. src/kernel/misc.c    
  794. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  795. 08800 /* This file contains a collection of miscellaneous procedures:
  796. 08801  *      mem_init:       initialize memory tables.  Some memory is reported
  797. 08802  *                      by the BIOS, some is guesstimated and checked later
  798. 08803  *      env_parse       parse environment variable.
  799. 08804  *      bad_assertion   for debugging
  800. 08805  *      bad_compare     for debugging
  801. 08806  */
  802. 08807
  803. 08808 #include "kernel.h"
  804. 08809 #include "assert.h"
  805. 08810 #include <stdlib.h>
  806. 08811 #include <minix/com.h>
  807. 08812
  808. 08813 #define EM_BASE     0x100000L   /* base of extended memory on AT's */
  809. 08814 #define SHADOW_BASE 0xFA0000L   /* base of RAM shadowing ROM on some AT's */
  810. 08815 #define SHADOW_MAX  0x060000L   /* maximum usable shadow memory (16M limit) */
  811. 08816
  812. 08817 /*=========================================================================*
  813. 08818  *                              mem_init                                   *
  814. 08819  *=========================================================================*/
  815. 08820 PUBLIC void mem_init()
  816. 08821 {
  817. 08822 /* Initialize the memory size tables.  This is complicated by fragmentation
  818. 08823  * and different access strategies for protected mode.  There must be a
  819. 08824  * chunk at 0 big enough to hold Minix proper.  For 286 and 386 processors,
  820. 08825  * there can be extended memory (memory above 1MB).  This usually starts at
  821. 08826  * 1MB, but there may be another chunk just below 16MB, reserved under DOS
  822. 08827  * for shadowing ROM, but available to Minix if the hardware can be re-mapped.
  823. 08828  * In protected mode, extended memory is accessible assuming CLICK_SIZE is
  824. 08829  * large enough, and is treated as ordinary memory.
  825. 08830  */
  826. 08831
  827. 08832   u32_t ext_clicks;
  828. 08833   phys_clicks max_clicks;
  829. 08834
  830. 08835   /* Get the size of ordinary memory from the BIOS. */
  831. 08836   mem[0].size = k_to_click(low_memsize);        /* base = 0 */
  832. 08837
  833. 08838   if (pc_at && protected_mode) {
  834. 08839         /* Get the size of extended memory from the BIOS.  This is special
  835. 08840          * except in protected mode, but protected mode is now normal.
  836. 08841          * Note that no more than 16M can be addressed in 286 mode, so make
  837. 08842          * sure that the highest memory address fits in a short when counted
  838. 08843          * in clicks.
  839. 08844          */
  840. 08845         ext_clicks = k_to_click((u32_t) ext_memsize);
  841. 08846         max_clicks = USHRT_MAX - (EM_BASE >> CLICK_SHIFT);
  842. 08847         mem[1].size = MIN(ext_clicks, max_clicks);
  843. 08848         mem[1].base = EM_BASE >> CLICK_SHIFT;
  844. 08849
  845. 08850         if (ext_memsize <= (unsigned) ((SHADOW_BASE - EM_BASE) / 1024)
  846. 08851                         && check_mem(SHADOW_BASE, SHADOW_MAX) == SHADOW_MAX) {
  847. 08852                 /* Shadow ROM memory. */
  848. 08853                 mem[2].size = SHADOW_MAX >> CLICK_SHIFT;
  849. 08854                 mem[2].base = SHADOW_BASE >> CLICK_SHIFT;
  850. 08855         }
  851. 08856   }
  852. 08857
  853. 08858   /* Total system memory. */
  854. 08859   tot_mem_size = mem[0].size + mem[1].size + mem[2].size;
  855. 08860 }
  856. 08862 /*=========================================================================*
  857. 08863  *                              env_parse                                  *
  858. 08864  *=========================================================================*/
  859. 08865 PUBLIC int env_parse(env, fmt, field, param, min, max)
  860. 08866 char *env;              /* environment variable to inspect */
  861. 08867 char *fmt;              /* template to parse it with */
  862. 08868 int field;              /* field number of value to return */
  863. 08869 long *param;            /* address of parameter to get */
  864. 08870 long min, max;          /* minimum and maximum values for the parameter */
  865. 08871 {
  866. 08872 /* Parse an environment variable setting, something like "DPETH0=300:3".
  867. 08873  * Panic if the parsing fails.  Return EP_UNSET if the environment variable
  868. 08874  * is not set, EP_OFF if it is set to "off", EP_ON if set to "on" or a
  869. 08875  * field is left blank, or EP_SET if a field is given (return value through
  870. 08876  * *param).  Commas and colons may be used in the environment and format
  871. 08877  * string, fields in the environment string may be empty, and punctuation
  872. 08878  * may be missing to skip fields.  The format string contains characters
  873. 08879  * 'd', 'o', 'x' and 'c' to indicate that 10, 8, 16, or 0 is used as the
  874. 08880  * last argument to strtol.
  875. 08881  */
  876. 08882
  877. 08883   char *val, *end;
  878. 08884   long newpar;
  879. 08885   int i = 0, radix, r;
  880. 08886
  881. 08887   if ((val = k_getenv(env)) == NIL_PTR) return(EP_UNSET);
  882. 08888   if (strcmp(val, "off") == 0) return(EP_OFF);
  883. 08889   if (strcmp(val, "on") == 0) return(EP_ON);
  884. 08890
  885. 08891   r = EP_ON;
  886. 08892   for (;;) {
  887. 08893         while (*val == ' ') val++;
  888. 08894
  889. 08895         if (*val == 0) return(r);       /* the proper exit point */
  890. 08896
  891. 08897         if (*fmt == 0) break;           /* too many values */
  892. 08898
  893. 08899         if (*val == ',' || *val == ':') {
  894. 08900                 /* Time to go to the next field. */
  895. 08901                 if (*fmt == ',' || *fmt == ':') i++;
  896. 08902                 if (*fmt++ == *val) val++;
  897. 08903         } else {
  898. 08904                 /* Environment contains a value, get it. */
  899. 08905                 switch (*fmt) {
  900. 08906                 case 'd':       radix =   10;   break;
  901. 08907                 case 'o':       radix =  010;   break;
  902. 08908                 case 'x':       radix = 0x10;   break;
  903. 08909                 case 'c':       radix =    0;   break;
  904. 08910                 default:        goto badenv;
  905. 08911                 }
  906. 08912                 newpar = strtol(val, &end, radix);
  907. 08913
  908. 08914                 if (end == val) break;  /* not a number */
  909. 08915                 val = end;
  910. 08916
  911. 08917                 if (i == field) {
  912. 08918                         /* The field requested. */
  913. 08919                         if (newpar < min || newpar > max) break;
  914. 08920                         *param = newpar;
  915. 08921                         r = EP_SET;
  916. 08922                 }
  917. 08923         }
  918. 08924   }
  919. 08925 badenv:
  920. 08926   printf("Bad environment setting: '%s = %s'n", env, k_getenv(env));
  921. 08927   panic("", NO_NUM);
  922. 08928   /*NOTREACHED*/
  923. 08929 }
  924. 08931 #if DEBUG
  925. 08932 /*=========================================================================*
  926. 08933  *                              bad_assertion                              *
  927. 08934  *=========================================================================*/
  928. 08935 PUBLIC void bad_assertion(file, line, what)
  929. 08936 char *file;
  930. 08937 int line;
  931. 08938 char *what;
  932. 08939 {
  933. 08940   printf("panic at %s(%d): assertion "%s" failedn", file, line, what);
  934. 08941   panic(NULL, NO_NUM);
  935. 08942 }
  936. 08944 /*=========================================================================*
  937. 08945  *                              bad_compare                                *
  938. 08946  *=========================================================================*/
  939. 08947 PUBLIC void bad_compare(file, line, lhs, what, rhs)
  940. 08948 char *file;
  941. 08949 int line;
  942. 08950 int lhs;
  943. 08951 char *what;
  944. 08952 int rhs;
  945. 08953 {
  946. 08954   printf("panic at %s(%d): compare (%d) %s (%d) failedn",
  947. 08955         file, line, lhs, what, rhs);
  948. 08956   panic(NULL, NO_NUM);
  949. 08957 }
  950. 08958 #endif /* DEBUG */
  951. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  952. src/kernel/driver.h    
  953. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  954. 09000 /* Types and constants shared between the generic and device dependent
  955. 09001  * device driver code.
  956. 09002  */
  957. 09003
  958. 09004 #include <minix/callnr.h>
  959. 09005 #include <minix/com.h>
  960. 09006 #include "proc.h"
  961. 09007 #include <minix/partition.h>
  962. 09008
  963. 09009 /* Info about and entry points into the device dependent code. */
  964. 09010 struct driver {
  965. 09011   _PROTOTYPE( char *(*dr_name), (void) );
  966. 09012   _PROTOTYPE( int (*dr_open), (struct driver *dp, message *m_ptr) );
  967. 09013   _PROTOTYPE( int (*dr_close), (struct driver *dp, message *m_ptr) );
  968. 09014   _PROTOTYPE( int (*dr_ioctl), (struct driver *dp, message *m_ptr) );
  969. 09015   _PROTOTYPE( struct device *(*dr_prepare), (int device) );
  970. 09016   _PROTOTYPE( int (*dr_schedule), (int proc_nr, struct iorequest_s *request) );
  971. 09017   _PROTOTYPE( int (*dr_finish), (void) );
  972. 09018   _PROTOTYPE( void (*dr_cleanup), (void) );
  973. 09019   _PROTOTYPE( void (*dr_geometry), (struct partition *entry) );
  974. 09020 };
  975. 09021
  976. 09022 #if (CHIP == INTEL)
  977. 09023
  978. 09024 /* Number of bytes you can DMA before hitting a 64K boundary: */
  979. 09025 #define dma_bytes_left(phys)    
  980. 09026    ((unsigned) (sizeof(int) == 2 ? 0 : 0x10000) - (unsigned) ((phys) & 0xFFFF))
  981. 09027
  982. 09028 #endif /* CHIP == INTEL */
  983. 09029
  984. 09030 /* Base and size of a partition in bytes. */
  985. 09031 struct device {
  986. 09032   unsigned long dv_base;
  987. 09033   unsigned long dv_size;
  988. 09034 };
  989. 09035
  990. 09036 #define NIL_DEV         ((struct device *) 0)
  991. 09037
  992. 09038 /* Functions defined by driver.c: */
  993. 09039 _PROTOTYPE( void driver_task, (struct driver *dr) );
  994. 09040 _PROTOTYPE( int do_rdwt, (struct driver *dr, message *m_ptr) );
  995. 09041 _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *m_ptr) );
  996. 09042 _PROTOTYPE( char *no_name, (void) );
  997. 09043 _PROTOTYPE( int do_nop, (struct driver *dp, message *m_ptr) );
  998. 09044 _PROTOTYPE( int nop_finish, (void) );
  999. 09045 _PROTOTYPE( void nop_cleanup, (void) );
  1000. 09046 _PROTOTYPE( void clock_mess, (int ticks, watchdog_t func) );
  1001. 09047 _PROTOTYPE( int do_diocntl, (struct driver *dr, message *m_ptr) );
  1002. 09048
  1003. 09049 /* Parameters for the disk drive. */
  1004. 09050 #define SECTOR_SIZE      512    /* physical sector size in bytes */
  1005. 09051 #define SECTOR_SHIFT       9    /* for division */
  1006. 09052 #define SECTOR_MASK      511    /* and remainder */
  1007. 09053
  1008. 09054 /* Size of the DMA buffer buffer in bytes. */
  1009. 09055 #define DMA_BUF_SIZE    (DMA_SECTORS * SECTOR_SIZE)
  1010. 09056
  1011. 09057 #if (CHIP == INTEL)
  1012. 09058 extern u8_t *tmp_buf;                   /* the DMA buffer */
  1013. 09059 #else
  1014. 09060 extern u8_t tmp_buf[];                  /* the DMA buffer */
  1015. 09061 #endif
  1016. 09062 extern phys_bytes tmp_phys;             /* phys address of DMA buffer */
  1017. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1018. src/kernel/driver.c    
  1019. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1020. 09100 /* This file contains device independent device driver interface.
  1021. 09101  *                                                      Author: Kees J. Bot.
  1022. 09102  *
  1023. 09103  * The drivers support the following operations (using message format m2):
  1024. 09104  *
  1025. 09105  *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
  1026. 09106  * ----------------------------------------------------------------
  1027. 09107  * |  DEV_OPEN  | device  | proc nr |         |         |         |
  1028. 09108  * |------------+---------+---------+---------+---------+---------|
  1029. 09109  * |  DEV_CLOSE | device  | proc nr |         |         |         |
  1030. 09110  * |------------+---------+---------+---------+---------+---------|
  1031. 09111  * |  DEV_READ  | device  | proc nr |  bytes  |  offset | buf ptr |
  1032. 09112  * |------------+---------+---------+---------+---------+---------|
  1033. 09113  * |  DEV_WRITE | device  | proc nr |  bytes  |  offset | buf ptr |
  1034. 09114  * |------------+---------+---------+---------+---------+---------|
  1035. 09115  * |SCATTERED_IO| device  | proc nr | requests|         | iov ptr |
  1036. 09116  * ----------------------------------------------------------------
  1037. 09117  * |  DEV_IOCTL | device  | proc nr |func code|         | buf ptr |
  1038. 09118  * ----------------------------------------------------------------
  1039. 09119  *
  1040. 09120  * The file contains one entry point:
  1041. 09121  *
  1042. 09122  *   driver_task:       called by the device dependent task entry
  1043. 09123  *
  1044. 09124  *
  1045. 09125  * Constructed 92/04/02 by Kees J. Bot from the old AT wini and floppy driver.
  1046. 09126  */
  1047. 09127
  1048. 09128 #include "kernel.h"
  1049. 09129 #include <sys/ioctl.h>
  1050. 09130 #include "driver.h"
  1051. 09131
  1052. 09132 #define BUF_EXTRA       0
  1053. 09133
  1054. 09134 /* Claim space for variables. */
  1055. 09135 PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE + BUF_EXTRA];
  1056. 09136 u8_t *tmp_buf;                  /* the DMA buffer eventually */
  1057. 09137 phys_bytes tmp_phys;            /* phys address of DMA buffer */
  1058. 09138
  1059. 09139 FORWARD _PROTOTYPE( void init_buffer, (void) );
  1060. 09140
  1061. 09141 /*===========================================================================*
  1062. 09142  *                              driver_task                                  *
  1063. 09143  *===========================================================================*/
  1064. 09144 PUBLIC void driver_task(dp)
  1065. 09145 struct driver *dp;      /* Device dependent entry points. */
  1066. 09146 {
  1067. 09147 /* Main program of any device driver task. */
  1068. 09148
  1069. 09149   int r, caller, proc_nr;
  1070. 09150   message mess;
  1071. 09151
  1072. 09152   init_buffer();        /* Get a DMA buffer. */
  1073. 09153
  1074. 09154   /* Here is the main loop of the disk task.  It waits for a message, carries
  1075. 09155    * it out, and sends a reply.
  1076. 09156    */
  1077. 09157
  1078. 09158   while (TRUE) {
  1079. 09159         /* First wait for a request to read or write a disk block. */
  1080. 09160         receive(ANY, &mess);
  1081. 09161
  1082. 09162         caller = mess.m_source;
  1083. 09163         proc_nr = mess.PROC_NR;
  1084. 09164
  1085. 09165         switch (caller) {
  1086. 09166         case HARDWARE:
  1087. 09167                 /* Leftover interrupt. */
  1088. 09168                 continue;
  1089. 09169         case FS_PROC_NR:
  1090. 09170                 /* The only legitimate caller. */
  1091. 09171                 break;
  1092. 09172         default:
  1093. 09173                 printf("%s: got message from %dn", (*dp->dr_name)(), caller);
  1094. 09174                 continue;
  1095. 09175         }
  1096. 09176
  1097. 09177         /* Now carry out the work. */
  1098. 09178         switch(mess.m_type) {
  1099. 09179             case DEV_OPEN:      r = (*dp->dr_open)(dp, &mess);  break;
  1100. 09180             case DEV_CLOSE:     r = (*dp->dr_close)(dp, &mess); break;
  1101. 09181             case DEV_IOCTL:     r = (*dp->dr_ioctl)(dp, &mess); break;
  1102. 09182
  1103. 09183             case DEV_READ:
  1104. 09184             case DEV_WRITE:     r = do_rdwt(dp, &mess);         break;
  1105. 09185
  1106. 09186             case SCATTERED_IO:  r = do_vrdwt(dp, &mess);        break;
  1107. 09187             default:            r = EINVAL;                     break;
  1108. 09188         }
  1109. 09189
  1110. 09190         /* Clean up leftover state. */
  1111. 09191         (*dp->dr_cleanup)();
  1112. 09192
  1113. 09193         /* Finally, prepare and send the reply message. */
  1114. 09194         mess.m_type = TASK_REPLY;
  1115. 09195         mess.REP_PROC_NR = proc_nr;
  1116. 09196
  1117. 09197         mess.REP_STATUS = r;    /* # of bytes transferred or error code */
  1118. 09198         send(caller, &mess);    /* send reply to caller */
  1119. 09199   }
  1120. 09200 }
  1121. 09202 /*===========================================================================*
  1122. 09203  *                              init_buffer                                  *
  1123. 09204  *===========================================================================*/
  1124. 09205 PRIVATE void init_buffer()
  1125. 09206 {
  1126. 09207 /* Select a buffer that can safely be used for dma transfers.  It may also
  1127. 09208  * be used to read partition tables and such.  Its absolute address is
  1128. 09209  * 'tmp_phys', the normal address is 'tmp_buf'.
  1129. 09210  */
  1130. 09211
  1131. 09212   tmp_buf = buffer;
  1132. 09213   tmp_phys = vir2phys(buffer);
  1133. 09214
  1134. 09215   if (tmp_phys == 0) panic("no DMA buffer", NO_NUM);
  1135. 09216
  1136. 09217   if (dma_bytes_left(tmp_phys) < DMA_BUF_SIZE) {
  1137. 09218         /* First half of buffer crosses a 64K boundary, can't DMA into that */
  1138. 09219         tmp_buf += DMA_BUF_SIZE;
  1139. 09220         tmp_phys += DMA_BUF_SIZE;
  1140. 09221   }
  1141. 09222 }
  1142. 09224 /*===========================================================================*
  1143. 09225  *                              do_rdwt                                      *
  1144. 09226  *===========================================================================*/
  1145. 09227 PUBLIC int do_rdwt(dp, m_ptr)
  1146. 09228 struct driver *dp;              /* device dependent entry points */
  1147. 09229 message *m_ptr;                 /* pointer to read or write message */
  1148. 09230 {
  1149. 09231 /* Carry out a single read or write request. */
  1150. 09232   struct iorequest_s ioreq;
  1151. 09233   int r;
  1152. 09234
  1153. 09235   if (m_ptr->COUNT <= 0) return(EINVAL);
  1154. 09236
  1155. 09237   if ((*dp->dr_prepare)(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  1156. 09238
  1157. 09239   ioreq.io_request = m_ptr->m_type;
  1158. 09240   ioreq.io_buf = m_ptr->ADDRESS;
  1159. 09241   ioreq.io_position = m_ptr->POSITION;
  1160. 09242   ioreq.io_nbytes = m_ptr->COUNT;
  1161. 09243
  1162. 09244   r = (*dp->dr_schedule)(m_ptr->PROC_NR, &ioreq);
  1163. 09245
  1164. 09246   if (r == OK) (void) (*dp->dr_finish)();
  1165. 09247
  1166. 09248   r = ioreq.io_nbytes;
  1167. 09249   return(r < 0 ? r : m_ptr->COUNT - r);
  1168. 09250 }
  1169. 09252 /*==========================================================================*
  1170. 09253  *                              do_vrdwt                                    *
  1171. 09254  *==========================================================================*/
  1172. 09255 PUBLIC int do_vrdwt(dp, m_ptr)
  1173. 09256 struct driver *dp;      /* device dependent entry points */
  1174. 09257 message *m_ptr;         /* pointer to read or write message */
  1175. 09258 {
  1176. 09259 /* Fetch a vector of i/o requests.  Handle requests one at a time.  Return
  1177. 09260  * status in the vector.
  1178. 09261  */
  1179. 09262
  1180. 09263   struct iorequest_s *iop;
  1181. 09264   static struct iorequest_s iovec[NR_IOREQS];
  1182. 09265   phys_bytes iovec_phys;
  1183. 09266   unsigned nr_requests;
  1184. 09267   int request;
  1185. 09268   int r;
  1186. 09269   phys_bytes user_iovec_phys;
  1187. 09270
  1188. 09271   nr_requests = m_ptr->COUNT;
  1189. 09272
  1190. 09273   if (nr_requests > sizeof iovec / sizeof iovec[0])
  1191. 09274         panic("FS passed too big an I/O vector", nr_requests);
  1192. 09275
  1193. 09276   iovec_phys = vir2phys(iovec);
  1194. 09277   user_iovec_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
  1195. 09278                          (vir_bytes) (nr_requests * sizeof iovec[0]));
  1196. 09279
  1197. 09280   if (user_iovec_phys == 0)
  1198. 09281         panic("FS passed a bad I/O vector", (int) m_ptr->ADDRESS);
  1199. 09282
  1200. 09283   phys_copy(user_iovec_phys, iovec_phys,
  1201. 09284                             (phys_bytes) nr_requests * sizeof iovec[0]);
  1202. 09285
  1203. 09286   if ((*dp->dr_prepare)(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  1204. 09287
  1205. 09288   for (request = 0, iop = iovec; request < nr_requests; request++, iop++) {
  1206. 09289         if ((r = (*dp->dr_schedule)(m_ptr->PROC_NR, iop)) != OK) break;
  1207. 09290   }
  1208. 09291
  1209. 09292   if (r == OK) (void) (*dp->dr_finish)();
  1210. 09293
  1211. 09294   phys_copy(iovec_phys, user_iovec_phys,
  1212. 09295                             (phys_bytes) nr_requests * sizeof iovec[0]);
  1213. 09296   return(OK);
  1214. 09297 }
  1215. 09299 /*===========================================================================*
  1216. 09300  *                              no_name                                      *
  1217. 09301  *===========================================================================*/
  1218. 09302 PUBLIC char *no_name()
  1219. 09303 {
  1220. 09304 /* If no specific name for the device. */
  1221. 09305
  1222. 09306   return(tasktab[proc_number(proc_ptr) + NR_TASKS].name);
  1223. 09307 }
  1224. 09309 /*============================================================================*
  1225. 09310  *                              do_nop                                        *
  1226. 09311  *============================================================================*/
  1227. 09312 PUBLIC int do_nop(dp, m_ptr)
  1228. 09313 struct driver *dp;
  1229. 09314 message *m_ptr;
  1230. 09315 {
  1231. 09316 /* Nothing there, or nothing to do. */
  1232. 09317
  1233. 09318   switch (m_ptr->m_type) {
  1234. 09319   case DEV_OPEN:        return(ENODEV);
  1235. 09320   case DEV_CLOSE:       return(OK);
  1236. 09321   case DEV_IOCTL:       return(ENOTTY);
  1237. 09322   default:              return(EIO);
  1238. 09323   }
  1239. 09324 }
  1240. 09326 /*===========================================================================*
  1241. 09327  *                              nop_finish                                   *
  1242. 09328  *===========================================================================*/
  1243. 09329 PUBLIC int nop_finish()
  1244. 09330 {
  1245. 09331 /* Nothing to finish, all the work has been done by dp->dr_schedule. */
  1246. 09332   return(OK);
  1247. 09333 }
  1248. 09335 /*===========================================================================*
  1249. 09336  *                              nop_cleanup                                  *
  1250. 09337  *===========================================================================*/
  1251. 09338 PUBLIC void nop_cleanup()
  1252. 09339 {
  1253. 09340 /* Nothing to clean up. */
  1254. 09341 }
  1255. 09343 /*===========================================================================*
  1256. 09344  *                              clock_mess                                   *
  1257. 09345  *===========================================================================*/
  1258. 09346 PUBLIC void clock_mess(ticks, func)
  1259. 09347 int ticks;                      /* how many clock ticks to wait */
  1260. 09348 watchdog_t func;                /* function to call upon time out */
  1261. 09349 {
  1262. 09350 /* Send the clock task a message. */
  1263. 09351
  1264. 09352   message mess;
  1265. 09353
  1266. 09354   mess.m_type = SET_ALARM;
  1267. 09355   mess.CLOCK_PROC_NR = proc_number(proc_ptr);
  1268. 09356   mess.DELTA_TICKS = (long) ticks;
  1269. 09357   mess.FUNC_TO_CALL = (sighandler_t) func;
  1270. 09358   sendrec(CLOCK, &mess);
  1271. 09359 }
  1272. 09361 /*============================================================================*
  1273. 09362  *                              do_diocntl                                    *
  1274. 09363  *============================================================================*/
  1275. 09364 PUBLIC int do_diocntl(dp, m_ptr)
  1276. 09365 struct driver *dp;
  1277. 09366 message *m_ptr;                 /* pointer to ioctl request */
  1278. 09367 {
  1279. 09368 /* Carry out a partition setting/getting request. */
  1280. 09369   struct device *dv;
  1281. 09370   phys_bytes user_phys, entry_phys;
  1282. 09371   struct partition entry;
  1283. 09372
  1284. 09373   if (m_ptr->REQUEST != DIOCSETP && m_ptr->REQUEST != DIOCGETP) return(ENOTTY);
  1285. 09374
  1286. 09375   /* Decode the message parameters. */
  1287. 09376   if ((dv = (*dp->dr_prepare)(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO);
  1288. 09377
  1289. 09378   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, sizeof(entry));
  1290. 09379   if (user_phys == 0) return(EFAULT);
  1291. 09380
  1292. 09381   entry_phys = vir2phys(&entry);
  1293. 09382
  1294. 09383   if (m_ptr->REQUEST == DIOCSETP) {
  1295. 09384         /* Copy just this one partition table entry. */
  1296. 09385         phys_copy(user_phys, entry_phys, (phys_bytes) sizeof(entry));
  1297. 09386         dv->dv_base = entry.base;
  1298. 09387         dv->dv_size = entry.size;
  1299. 09388   } else {
  1300. 09389         /* Return a partition table entry and the geometry of the drive. */
  1301. 09390         entry.base = dv->dv_base;
  1302. 09391         entry.size = dv->dv_size;
  1303. 09392         (*dp->dr_geometry)(&entry);
  1304. 09393         phys_copy(entry_phys, user_phys, (phys_bytes) sizeof(entry));
  1305. 09394   }
  1306. 09395   return(OK);
  1307. 09396 }
  1308. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1309. src/kernel/drvlib.h    
  1310. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1311. 09400 /* IBM device driver definitions                        Author: Kees J. Bot
  1312. 09401  *                                                              7 Dec 1995
  1313. 09402  */
  1314. 09403
  1315. 09404 #include <ibm/partition.h>
  1316. 09405
  1317. 09406 _PROTOTYPE( void partition, (struct driver *dr, int device, int style) );
  1318. 09407
  1319. 09408 /* BIOS parameter table layout. */
  1320. 09409 #define bp_cylinders(t)         (* (u16_t *) (&(t)[0]))
  1321. 09410 #define bp_heads(t)             (* (u8_t *)  (&(t)[2]))
  1322. 09411 #define bp_reduced_wr(t)        (* (u16_t *) (&(t)[3]))
  1323. 09412 #define bp_precomp(t)           (* (u16_t *) (&(t)[5]))
  1324. 09413 #define bp_max_ecc(t)           (* (u8_t *)  (&(t)[7]))
  1325. 09414 #define bp_ctlbyte(t)           (* (u8_t *)  (&(t)[8]))
  1326. 09415 #define bp_landingzone(t)       (* (u16_t *) (&(t)[12]))
  1327. 09416 #define bp_sectors(t)           (* (u8_t *)  (&(t)[14]))
  1328. 09417
  1329. 09418 /* Miscellaneous. */
  1330. 09419 #define DEV_PER_DRIVE   (1 + NR_PARTITIONS)
  1331. 09420 #define MINOR_hd1a      128
  1332. 09421 #define MINOR_fd0a      (28<<2)
  1333. 09422 #define P_FLOPPY        0
  1334. 09423 #define P_PRIMARY       1
  1335. 09424 #define P_SUB           2
  1336. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1337. src/kernel/drvlib.c    
  1338. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1339. 09500 /* IBM device driver utility functions.                 Author: Kees J. Bot
  1340. 09501  *                                                              7 Dec 1995
  1341. 09502  * Entry point:
  1342. 09503  *   partition: partition a disk to the partition table(s) on it.
  1343. 09504  */
  1344. 09505
  1345. 09506 #include "kernel.h"
  1346. 09507 #include "driver.h"
  1347. 09508 #include "drvlib.h"
  1348. 09509
  1349. 09510
  1350. 09511 FORWARD _PROTOTYPE( void extpartition, (struct driver *dp, int extdev,
  1351. 09512                                                 unsigned long extbase) );
  1352. 09513 FORWARD _PROTOTYPE( int get_part_table, (struct driver *dp, int device,
  1353. 09514                         unsigned long offset, struct part_entry *table) );
  1354. 09515 FORWARD _PROTOTYPE( void sort, (struct part_entry *table) );
  1355. 09516
  1356. 09517
  1357. 09518 /*============================================================================*
  1358. 09519  *                              partition                                     *
  1359. 09520  *============================================================================*/
  1360. 09521 PUBLIC void partition(dp, device, style)
  1361. 09522 struct driver *dp;      /* device dependent entry points */
  1362. 09523 int device;             /* device to partition */
  1363. 09524 int style;              /* partitioning style: floppy, primary, sub. */
  1364. 09525 {
  1365. 09526 /* This routine is called on first open to initialize the partition tables
  1366. 09527  * of a device.  It makes sure that each partition falls safely within the
  1367. 09528  * device's limits.  Depending on the partition style we are either making
  1368. 09529  * floppy partitions, primary partitions or subpartitions.  Only primary
  1369. 09530  * partitions are sorted, because they are shared with other operating
  1370. 09531  * systems that expect this.
  1371. 09532  */
  1372. 09533   struct part_entry table[NR_PARTITIONS], *pe;
  1373. 09534   int disk, par;
  1374. 09535   struct device *dv;
  1375. 09536   unsigned long base, limit, part_limit;
  1376. 09537
  1377. 09538   /* Get the geometry of the device to partition */
  1378. 09539   if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV || dv->dv_size == 0) return;
  1379. 09540   base = dv->dv_base >> SECTOR_SHIFT;
  1380. 09541   limit = base + (dv->dv_size >> SECTOR_SHIFT);
  1381. 09542
  1382. 09543   /* Read the partition table for the device. */
  1383. 09544   if (!get_part_table(dp, device, 0L, table)) return;
  1384. 09545
  1385. 09546   /* Compute the device number of the first partition. */
  1386. 09547   switch (style) {
  1387. 09548   case P_FLOPPY:
  1388. 09549         device += MINOR_fd0a;
  1389. 09550         break;
  1390. 09551   case P_PRIMARY:
  1391. 09552         sort(table);            /* sort a primary partition table */
  1392. 09553         device += 1;
  1393. 09554         break;
  1394. 09555   case P_SUB:
  1395. 09556         disk = device / DEV_PER_DRIVE;
  1396. 09557         par = device % DEV_PER_DRIVE - 1;
  1397. 09558         device = MINOR_hd1a + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
  1398. 09559   }
  1399. 09560
  1400. 09561   /* Find an array of devices. */
  1401. 09562   if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV) return;
  1402. 09563
  1403. 09564   /* Set the geometry of the partitions from the partition table. */
  1404. 09565   for (par = 0; par < NR_PARTITIONS; par++, dv++) {
  1405. 09566         /* Shrink the partition to fit within the device. */
  1406. 09567         pe = &table[par];
  1407. 09568         part_limit = pe->lowsec + pe->size;
  1408. 09569         if (part_limit < pe->lowsec) part_limit = limit;
  1409. 09570         if (part_limit > limit) part_limit = limit;
  1410. 09571         if (pe->lowsec < base) pe->lowsec = base;
  1411. 09572         if (part_limit < pe->lowsec) part_limit = pe->lowsec;
  1412. 09573
  1413. 09574         dv->dv_base = pe->lowsec << SECTOR_SHIFT;
  1414. 09575         dv->dv_size = (part_limit - pe->lowsec) << SECTOR_SHIFT;
  1415. 09576
  1416. 09577         if (style == P_PRIMARY) {
  1417. 09578                 /* Each Minix primary partition can be subpartitioned. */
  1418. 09579                 if (pe->sysind == MINIX_PART)
  1419. 09580                         partition(dp, device + par, P_SUB);
  1420. 09581
  1421. 09582                 /* An extended partition has logical partitions. */
  1422. 09583                 if (pe->sysind == EXT_PART)
  1423. 09584                         extpartition(dp, device + par, pe->lowsec);
  1424. 09585         }
  1425. 09586   }
  1426. 09587 }
  1427. 09590 /*============================================================================*
  1428. 09591  *                              extpartition                                  *
  1429. 09592  *============================================================================*/
  1430. 09593 PRIVATE void extpartition(dp, extdev, extbase)
  1431. 09594 struct driver *dp;      /* device dependent entry points */
  1432. 09595 int extdev;             /* extended partition to scan */
  1433. 09596 unsigned long extbase;  /* sector offset of the base extended partition */
  1434. 09597 {
  1435. 09598 /* Extended partitions cannot be ignored alas, because people like to move
  1436. 09599  * files to and from DOS partitions.  Avoid reading this code, it's no fun.
  1437. 09600  */
  1438. 09601   struct part_entry table[NR_PARTITIONS], *pe;
  1439. 09602   int subdev, disk, par;
  1440. 09603   struct device *dv;
  1441. 09604   unsigned long offset, nextoffset;
  1442. 09605
  1443. 09606   disk = extdev / DEV_PER_DRIVE;
  1444. 09607   par = extdev % DEV_PER_DRIVE - 1;
  1445. 09608   subdev = MINOR_hd1a + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
  1446. 09609
  1447. 09610   offset = 0;
  1448. 09611   do {
  1449. 09612         if (!get_part_table(dp, extdev, offset, table)) return;
  1450. 09613         sort(table);
  1451. 09614
  1452. 09615         /* The table should contain one logical partition and optionally
  1453. 09616          * another extended partition.  (It's a linked list.)
  1454. 09617          */
  1455. 09618         nextoffset = 0;
  1456. 09619         for (par = 0; par < NR_PARTITIONS; par++) {
  1457. 09620                 pe = &table[par];
  1458. 09621                 if (pe->sysind == EXT_PART) {
  1459. 09622                         nextoffset = pe->lowsec;
  1460. 09623                 } else
  1461. 09624                 if (pe->sysind != NO_PART) {
  1462. 09625                         if ((dv = (*dp->dr_prepare)(subdev)) == NIL_DEV) return;
  1463. 09626
  1464. 09627                         dv->dv_base = (extbase + offset
  1465. 09628                                         + pe->lowsec) << SECTOR_SHIFT;
  1466. 09629                         dv->dv_size = pe->size << SECTOR_SHIFT;
  1467. 09630
  1468. 09631                         /* Out of devices? */
  1469. 09632                         if (++subdev % NR_PARTITIONS == 0) return;
  1470. 09633                 }
  1471. 09634         }
  1472. 09635   } while ((offset = nextoffset) != 0);
  1473. 09636 }
  1474. 09639 /*============================================================================*
  1475. 09640  *                              get_part_table                                *
  1476. 09641  *============================================================================*/
  1477. 09642 PRIVATE int get_part_table(dp, device, offset, table)
  1478. 09643 struct driver *dp;
  1479. 09644 int device;
  1480. 09645 unsigned long offset;           /* sector offset to the table */
  1481. 09646 struct part_entry *table;       /* four entries */
  1482. 09647 {
  1483. 09648 /* Read the partition table for the device, return true iff there were no
  1484. 09649  * errors.
  1485. 09650  */
  1486. 09651   message mess;
  1487. 09652
  1488. 09653   mess.DEVICE = device;
  1489. 09654   mess.POSITION = offset << SECTOR_SHIFT;
  1490. 09655   mess.COUNT = SECTOR_SIZE;
  1491. 09656   mess.ADDRESS = (char *) tmp_buf;
  1492. 09657   mess.PROC_NR = proc_number(proc_ptr);
  1493. 09658   mess.m_type = DEV_READ;
  1494. 09659
  1495. 09660   if (do_rdwt(dp, &mess) != SECTOR_SIZE) {
  1496. 09661         printf("%s: can't read partition tablen", (*dp->dr_name)());
  1497. 09662         return 0;
  1498. 09663   }
  1499. 09664   if (tmp_buf[510] != 0x55 || tmp_buf[511] != 0xAA) {
  1500. 09665         /* Invalid partition table. */
  1501. 09666         return 0;
  1502. 09667   }
  1503. 09668   memcpy(table, (tmp_buf + PART_TABLE_OFF), NR_PARTITIONS * sizeof(table[0]));
  1504. 09669   return 1;
  1505. 09670 }
  1506. 09673 /*===========================================================================*
  1507. 09674  *                              sort                                         *
  1508. 09675  *===========================================================================*/
  1509. 09676 PRIVATE void sort(table)
  1510. 09677 struct part_entry *table;
  1511. 09678 {
  1512. 09679 /* Sort a partition table. */
  1513. 09680   struct part_entry *pe, tmp;
  1514. 09681   int n = NR_PARTITIONS;
  1515. 09682
  1516. 09683   do {
  1517. 09684         for (pe = table; pe < table + NR_PARTITIONS-1; pe++) {
  1518. 09685                 if (pe[0].sysind == NO_PART
  1519. 09686                         || (pe[0].lowsec > pe[1].lowsec
  1520. 09687                                         && pe[1].sysind != NO_PART)) {
  1521. 09688                         tmp = pe[0]; pe[0] = pe[1]; pe[1] = tmp;
  1522. 09689                 }
  1523. 09690         }
  1524. 09691   } while (--n > 0);
  1525. 09692 }
  1526. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1527. src/kernel/memory.c    
  1528. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1529. 09700 /* This file contains the device dependent part of the drivers for the
  1530. 09701  * following special files:
  1531. 09702  *     /dev/null        - null device (data sink)
  1532. 09703  *     /dev/mem         - absolute memory
  1533. 09704  *     /dev/kmem        - kernel virtual memory
  1534. 09705  *     /dev/ram         - RAM disk
  1535. 09706  *
  1536. 09707  * The file contains one entry point:
  1537. 09708  *
  1538. 09709  *   mem_task:  main entry when system is brought up
  1539. 09710  *
  1540. 09711  *  Changes:
  1541. 09712  *      20 Apr  1992 by Kees J. Bot: device dependent/independent split
  1542. 09713  */
  1543. 09714
  1544. 09715 #include "kernel.h"
  1545. 09716 #include "driver.h"
  1546. 09717 #include <sys/ioctl.h>
  1547. 09718
  1548. 09719 #define NR_RAMS            4    /* number of RAM-type devices */
  1549. 09720
  1550. 09721 PRIVATE struct device m_geom[NR_RAMS];  /* Base and size of each RAM disk */
  1551. 09722 PRIVATE int m_device;           /* current device */
  1552. 09723
  1553. 09724 FORWARD _PROTOTYPE( struct device *m_prepare, (int device) );
  1554. 09725 FORWARD _PROTOTYPE( int m_schedule, (int proc_nr, struct iorequest_s *iop) );
  1555. 09726 FORWARD _PROTOTYPE( int m_do_open, (struct driver *dp, message *m_ptr) );
  1556. 09727 FORWARD _PROTOTYPE( void m_init, (void) );
  1557. 09728 FORWARD _PROTOTYPE( int m_ioctl, (struct driver *dp, message *m_ptr) );
  1558. 09729 FORWARD _PROTOTYPE( void m_geometry, (struct partition *entry) );
  1559. 09730
  1560. 09731
  1561. 09732 /* Entry points to this driver. */
  1562. 09733 PRIVATE struct driver m_dtab = {
  1563. 09734   no_name,      /* current device's name */
  1564. 09735   m_do_open,    /* open or mount */
  1565. 09736   do_nop,       /* nothing on a close */
  1566. 09737   m_ioctl,      /* specify ram disk geometry */
  1567. 09738   m_prepare,    /* prepare for I/O on a given minor device */
  1568. 09739   m_schedule,   /* do the I/O */
  1569. 09740   nop_finish,   /* schedule does the work, no need to be smart */
  1570. 09741   nop_cleanup,  /* nothing's dirty */
  1571. 09742   m_geometry,   /* memory device "geometry" */
  1572. 09743 };
  1573. 09744
  1574. 09745
  1575. 09746 /*===========================================================================*
  1576. 09747  *                              mem_task                                     *
  1577. 09748  *===========================================================================*/
  1578. 09749 PUBLIC void mem_task()
  1579. 09750 {
  1580. 09751   m_init();
  1581. 09752   driver_task(&m_dtab);
  1582. 09753 }
  1583. 09756 /*===========================================================================*
  1584. 09757  *                              m_prepare                                    *
  1585. 09758  *===========================================================================*/
  1586. 09759 PRIVATE struct device *m_prepare(device)
  1587. 09760 int device;
  1588. 09761 {
  1589. 09762 /* Prepare for I/O on a device. */
  1590. 09763
  1591. 09764   if (device < 0 || device >= NR_RAMS) return(NIL_DEV);
  1592. 09765   m_device = device;
  1593. 09766
  1594. 09767   return(&m_geom[device]);
  1595. 09768 }
  1596. 09771 /*===========================================================================*
  1597. 09772  *                              m_schedule                                   *
  1598. 09773  *===========================================================================*/
  1599. 09774 PRIVATE int m_schedule(proc_nr, iop)
  1600. 09775 int proc_nr;                    /* process doing the request */
  1601. 09776 struct iorequest_s *iop;        /* pointer to read or write request */
  1602. 09777 {
  1603. 09778 /* Read or write /dev/null, /dev/mem, /dev/kmem, or /dev/ram. */
  1604. 09779
  1605. 09780   int device, count, opcode;
  1606. 09781   phys_bytes mem_phys, user_phys;
  1607. 09782   struct device *dv;
  1608. 09783
  1609. 09784   /* Type of request */
  1610. 09785   opcode = iop->io_request & ~OPTIONAL_IO;
  1611. 09786
  1612. 09787   /* Get minor device number and check for /dev/null. */
  1613. 09788   device = m_device;
  1614. 09789   dv = &m_geom[device];
  1615. 09790
  1616. 09791   /* Determine address where data is to go or to come from. */
  1617. 09792   user_phys = numap(proc_nr, (vir_bytes) iop->io_buf,
  1618. 09793                                                 (vir_bytes) iop->io_nbytes);
  1619. 09794   if (user_phys == 0) return(iop->io_nbytes = EINVAL);
  1620. 09795
  1621. 09796   if (device == NULL_DEV) {
  1622. 09797         /* /dev/null: Black hole. */
  1623. 09798         if (opcode == DEV_WRITE) iop->io_nbytes = 0;
  1624. 09799         count = 0;
  1625. 09800   } else {
  1626. 09801         /* /dev/mem, /dev/kmem, or /dev/ram: Check for EOF */
  1627. 09802         if (iop->io_position >= dv->dv_size) return(OK);
  1628. 09803         count = iop->io_nbytes;
  1629. 09804         if (iop->io_position + count > dv->dv_size)
  1630. 09805                 count = dv->dv_size - iop->io_position;
  1631. 09806   }
  1632. 09807
  1633. 09808   /* Set up 'mem_phys' for /dev/mem, /dev/kmem, or /dev/ram */
  1634. 09809   mem_phys = dv->dv_base + iop->io_position;
  1635. 09810
  1636. 09811   /* Book the number of bytes to be transferred in advance. */
  1637. 09812   iop->io_nbytes -= count;
  1638. 09813
  1639. 09814   if (count == 0) return(OK);
  1640. 09815
  1641. 09816   /* Copy the data. */
  1642. 09817   if (opcode == DEV_READ)
  1643. 09818         phys_copy(mem_phys, user_phys, (phys_bytes) count);
  1644. 09819   else
  1645. 09820         phys_copy(user_phys, mem_phys, (phys_bytes) count);
  1646. 09821
  1647. 09822   return(OK);
  1648. 09823 }
  1649. 09826 /*============================================================================*
  1650. 09827  *                              m_do_open                                     *
  1651. 09828  *============================================================================*/
  1652. 09829 PRIVATE int m_do_open(dp, m_ptr)
  1653. 09830 struct driver *dp;
  1654. 09831 message *m_ptr;
  1655. 09832 {
  1656. 09833 /* Check device number on open.  Give I/O privileges to a process opening
  1657. 09834  * /dev/mem or /dev/kmem.
  1658. 09835  */
  1659. 09836
  1660. 09837   if (m_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  1661. 09838
  1662. 09839   if (m_device == MEM_DEV || m_device == KMEM_DEV)
  1663. 09840         enable_iop(proc_addr(m_ptr->PROC_NR));
  1664. 09841
  1665. 09842   return(OK);
  1666. 09843 }
  1667. 09846 /*===========================================================================*
  1668. 09847  *                              m_init                                       *
  1669. 09848  *===========================================================================*/
  1670. 09849 PRIVATE void m_init()
  1671. 09850 {
  1672. 09851   /* Initialize this task. */
  1673. 09852   extern int _end;
  1674. 09853
  1675. 09854   m_geom[KMEM_DEV].dv_base = vir2phys(0);
  1676. 09855   m_geom[KMEM_DEV].dv_size = vir2phys(&_end);
  1677. 09856
  1678. 09857 #if (CHIP == INTEL)
  1679. 09858   if (!protected_mode) {
  1680. 09859         m_geom[MEM_DEV].dv_size =   0x100000;   /* 1M for 8086 systems */
  1681. 09860   } else {
  1682. 09861 #if _WORD_SIZE == 2
  1683. 09862         m_geom[MEM_DEV].dv_size =  0x1000000;   /* 16M for 286 systems */
  1684. 09863 #else
  1685. 09864         m_geom[MEM_DEV].dv_size = 0xFFFFFFFF;   /* 4G-1 for 386 systems */
  1686. 09865 #endif
  1687. 09866   }
  1688. 09867 #endif
  1689. 09868 }
  1690. 09871 /*===========================================================================*
  1691. 09872  *                              m_ioctl                                      *
  1692. 09873  *===========================================================================*/
  1693. 09874 PRIVATE int m_ioctl(dp, m_ptr)
  1694. 09875 struct driver *dp;
  1695. 09876 message *m_ptr;                 /* pointer to read or write message */
  1696. 09877 {
  1697. 09878 /* Set parameters for one of the RAM disks. */
  1698. 09879
  1699. 09880   unsigned long bytesize;
  1700. 09881   unsigned base, size;
  1701. 09882   struct memory *memp;
  1702. 09883   static struct psinfo psinfo = { NR_TASKS, NR_PROCS, (vir_bytes) proc, 0, 0 };
  1703. 09884   phys_bytes psinfo_phys;
  1704. 09885
  1705. 09886   switch (m_ptr->REQUEST) {
  1706. 09887   case MIOCRAMSIZE:
  1707. 09888         /* FS sets the RAM disk size. */
  1708. 09889         if (m_ptr->PROC_NR != FS_PROC_NR) return(EPERM);
  1709. 09890
  1710. 09891         bytesize = m_ptr->POSITION * BLOCK_SIZE;
  1711. 09892         size = (bytesize + CLICK_SHIFT-1) >> CLICK_SHIFT;
  1712. 09893
  1713. 09894         /* Find a memory chunk big enough for the RAM disk. */
  1714. 09895         memp= &mem[NR_MEMS];
  1715. 09896         while ((--memp)->size < size) {
  1716. 09897                 if (memp == mem) panic("RAM disk is too big", NO_NUM);
  1717. 09898         }
  1718. 09899         base = memp->base;
  1719. 09900         memp->base += size;
  1720. 09901         memp->size -= size;
  1721. 09902
  1722. 09903         m_geom[RAM_DEV].dv_base = (unsigned long) base << CLICK_SHIFT;
  1723. 09904         m_geom[RAM_DEV].dv_size = bytesize;
  1724. 09905         break;
  1725. 09906   case MIOCSPSINFO:
  1726. 09907         /* MM or FS set the address of their process table. */
  1727. 09908         if (m_ptr->PROC_NR == MM_PROC_NR) {
  1728. 09909                 psinfo.mproc = (vir_bytes) m_ptr->ADDRESS;
  1729. 09910         } else
  1730. 09911         if (m_ptr->PROC_NR == FS_PROC_NR) {
  1731. 09912                 psinfo.fproc = (vir_bytes) m_ptr->ADDRESS;
  1732. 09913         } else {
  1733. 09914                 return(EPERM);
  1734. 09915         }
  1735. 09916         break;
  1736. 09917   case MIOCGPSINFO:
  1737. 09918         /* The ps program wants the process table addresses. */
  1738. 09919         psinfo_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
  1739. 09920                                                         sizeof(psinfo));
  1740. 09921         if (psinfo_phys == 0) return(EFAULT);
  1741. 09922         phys_copy(vir2phys(&psinfo), psinfo_phys, (phys_bytes) sizeof(psinfo));
  1742. 09923         break;
  1743. 09924   default:
  1744. 09925         return(do_diocntl(&m_dtab, m_ptr));
  1745. 09926   }
  1746. 09927   return(OK);
  1747. 09928 }
  1748. 09931 /*============================================================================*
  1749. 09932  *                              m_geometry                                    *
  1750. 09933  *============================================================================*/
  1751. 09934 PRIVATE void m_geometry(entry)
  1752. 09935 struct partition *entry;
  1753. 09936 {
  1754. 09937   /* Memory devices don't have a geometry, but the outside world insists. */
  1755. 09938   entry->cylinders = (m_geom[m_device].dv_size >> SECTOR_SHIFT) / (64 * 32);
  1756. 09939   entry->heads = 64;
  1757. 09940   entry->sectors = 32;
  1758. 09941 }
  1759. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1760. src/kernel/wini.c    
  1761. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1762. 10000 /*      wini.c - choose a winchester driver.            Author: Kees J. Bot
  1763. 10001  *                                                              28 May 1994
  1764. 10002  * Several different winchester drivers may be compiled
  1765. 10003  * into the kernel, but only one may run.  That one is chosen here using
  1766. 10004  * the boot variable 'hd'.
  1767. 10005  */
  1768. 10006
  1769. 10007 #include "kernel.h"
  1770. 10008 #include "driver.h"
  1771. 10009
  1772. 10010 #if ENABLE_WINI
  1773. 10011
  1774. 10012 /* Map driver name to task function. */
  1775. 10013 struct hdmap {
  1776. 10014   char          *name;
  1777. 10015   task_t        *task;
  1778. 10016 } hdmap[] = {
  1779. 10017
  1780. 10018 #if ENABLE_AT_WINI
  1781. 10019   { "at",       at_winchester_task      },
  1782. 10020 #endif
  1783. 10021
  1784. 10022 #if ENABLE_BIOS_WINI
  1785. 10023   { "bios",     bios_winchester_task    },
  1786. 10024 #endif
  1787. 10025
  1788. 10026 #if ENABLE_ESDI_WINI
  1789. 10027   { "esdi",     esdi_winchester_task    },
  1790. 10028 #endif
  1791. 10029
  1792. 10030 #if ENABLE_XT_WINI
  1793. 10031   { "xt",       xt_winchester_task      },
  1794. 10032 #endif
  1795. 10033
  1796. 10034 };
  1797. 10035
  1798. 10036
  1799. 10037 /*===========================================================================*
  1800. 10038  *                              winchester_task                              *
  1801. 10039  *===========================================================================*/
  1802. 10040 PUBLIC void winchester_task()
  1803. 10041 {
  1804. 10042   /* Call the default or selected winchester task. */
  1805. 10043   char *hd;
  1806. 10044   struct hdmap *map;
  1807. 10045
  1808. 10046   hd = k_getenv("hd");
  1809. 10047
  1810. 10048   for (map = hdmap; map < hdmap + sizeof(hdmap)/sizeof(hdmap[0]); map++) {
  1811. 10049         if (hd == NULL || strcmp(hd, map->name) == 0) {
  1812. 10050                 /* Run the selected winchester task. */
  1813. 10051                 (*map->task)();
  1814. 10052         }
  1815. 10053   }
  1816. 10054   panic("no hd driver", NO_NUM);
  1817. 10055 }
  1818. 10056 #endif /* ENABLE_WINI */
  1819. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1820. src/kernel/at_wini.c    
  1821. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1822. 10100 /* This file contains the device dependent part of a driver for the IBM-AT
  1823. 10101  * winchester controller.
  1824. 10102  * It was written by Adri Koppes.
  1825. 10103  *
  1826. 10104  * The file contains one entry point:
  1827. 10105  *
  1828. 10106  *   at_winchester_task:        main entry when system is brought up
  1829. 10107  *
  1830. 10108  *
  1831. 10109  * Changes:
  1832. 10110  *      13 Apr 1992 by Kees J. Bot: device dependent/independent split.
  1833. 10111  */
  1834. 10112
  1835. 10113 #include "kernel.h"
  1836. 10114 #include "driver.h"
  1837. 10115 #include "drvlib.h"
  1838. 10116
  1839. 10117 #if ENABLE_AT_WINI
  1840. 10118
  1841. 10119 /* I/O Ports used by winchester disk controllers. */
  1842. 10120
  1843. 10121 /* Read and write registers */
  1844. 10122 #define REG_BASE0       0x1F0   /* base register of controller 0 */
  1845. 10123 #define REG_BASE1       0x170   /* base register of controller 1 */
  1846. 10124 #define REG_DATA            0   /* data register (offset from the base reg.) */
  1847. 10125 #define REG_PRECOMP         1   /* start of write precompensation */
  1848. 10126 #define REG_COUNT           2   /* sectors to transfer */
  1849. 10127 #define REG_SECTOR          3   /* sector number */
  1850. 10128 #define REG_CYL_LO          4   /* low byte of cylinder number */
  1851. 10129 #define REG_CYL_HI          5   /* high byte of cylinder number */
  1852. 10130 #define REG_LDH             6   /* lba, drive and head */
  1853. 10131 #define   LDH_DEFAULT           0xA0    /* ECC enable, 512 bytes per sector */
  1854. 10132 #define   LDH_LBA               0x40    /* Use LBA addressing */
  1855. 10133 #define   ldh_init(drive)       (LDH_DEFAULT | ((drive) << 4))
  1856. 10134
  1857. 10135 /* Read only registers */
  1858. 10136 #define REG_STATUS          7   /* status */
  1859. 10137 #define   STATUS_BSY            0x80    /* controller busy */
  1860. 10138 #define   STATUS_RDY            0x40    /* drive ready */
  1861. 10139 #define   STATUS_WF             0x20    /* write fault */
  1862. 10140 #define   STATUS_SC             0x10    /* seek complete (obsolete) */
  1863. 10141 #define   STATUS_DRQ            0x08    /* data transfer request */
  1864. 10142 #define   STATUS_CRD            0x04    /* corrected data */
  1865. 10143 #define   STATUS_IDX            0x02    /* index pulse */
  1866. 10144 #define   STATUS_ERR            0x01    /* error */
  1867. 10145 #define REG_ERROR           1   /* error code */
  1868. 10146 #define   ERROR_BB              0x80    /* bad block */
  1869. 10147 #define   ERROR_ECC             0x40    /* bad ecc bytes */
  1870. 10148 #define   ERROR_ID              0x10    /* id not found */
  1871. 10149 #define   ERROR_AC              0x04    /* aborted command */
  1872. 10150 #define   ERROR_TK              0x02    /* track zero error */
  1873. 10151 #define   ERROR_DM              0x01    /* no data address mark */
  1874. 10152
  1875. 10153 /* Write only registers */
  1876. 10154 #define REG_COMMAND         7   /* command */
  1877. 10155 #define   CMD_IDLE              0x00    /* for w_command: drive idle */
  1878. 10156 #define   CMD_RECALIBRATE       0x10    /* recalibrate drive */
  1879. 10157 #define   CMD_READ              0x20    /* read data */
  1880. 10158 #define   CMD_WRITE             0x30    /* write data */
  1881. 10159 #define   CMD_READVERIFY        0x40    /* read verify */
  1882. 10160 #define   CMD_FORMAT            0x50    /* format track */
  1883. 10161 #define   CMD_SEEK              0x70    /* seek cylinder */
  1884. 10162 #define   CMD_DIAG              0x90    /* execute device diagnostics */
  1885. 10163 #define   CMD_SPECIFY           0x91    /* specify parameters */
  1886. 10164 #define   ATA_IDENTIFY          0xEC    /* identify drive */
  1887. 10165 #define REG_CTL         0x206   /* control register */
  1888. 10166 #define   CTL_NORETRY           0x80    /* disable access retry */
  1889. 10167 #define   CTL_NOECC             0x40    /* disable ecc retry */
  1890. 10168 #define   CTL_EIGHTHEADS        0x08    /* more than eight heads */
  1891. 10169 #define   CTL_RESET             0x04    /* reset controller */
  1892. 10170 #define   CTL_INTDISABLE        0x02    /* disable interrupts */
  1893. 10171
  1894. 10172 /* Interrupt request lines. */
  1895. 10173 #define AT_IRQ0         14      /* interrupt number for controller 0 */
  1896. 10174 #define AT_IRQ1         15      /* interrupt number for controller 1 */
  1897. 10175
  1898. 10176 /* Common command block */
  1899. 10177 struct command {
  1900. 10178   u8_t  precomp;        /* REG_PRECOMP, etc. */
  1901. 10179   u8_t  count;
  1902. 10180   u8_t  sector;
  1903. 10181   u8_t  cyl_lo;
  1904. 10182   u8_t  cyl_hi;
  1905. 10183   u8_t  ldh;
  1906. 10184   u8_t  command;
  1907. 10185 };
  1908. 10186
  1909. 10187
  1910. 10188 /* Error codes */
  1911. 10189 #define ERR              (-1)   /* general error */
  1912. 10190 #define ERR_BAD_SECTOR   (-2)   /* block marked bad detected */
  1913. 10191
  1914. 10192 /* Some controllers don't interrupt, the clock will wake us up. */
  1915. 10193 #define WAKEUP          (32*HZ) /* drive may be out for 31 seconds max */
  1916. 10194
  1917. 10195 /* Miscellaneous. */
  1918. 10196 #define MAX_DRIVES         4    /* this driver supports 4 drives (hd0 - hd19) */
  1919. 10197 #if _WORD_SIZE > 2
  1920. 10198 #define MAX_SECS         256    /* controller can transfer this many sectors */
  1921. 10199 #else
  1922. 10200 #define MAX_SECS         127    /* but not to a 16 bit process */
  1923. 10201 #endif
  1924. 10202 #define MAX_ERRORS         4    /* how often to try rd/wt before quitting */
  1925. 10203 #define NR_DEVICES      (MAX_DRIVES * DEV_PER_DRIVE)
  1926. 10204 #define SUB_PER_DRIVE   (NR_PARTITIONS * NR_PARTITIONS)
  1927. 10205 #define NR_SUBDEVS      (MAX_DRIVES * SUB_PER_DRIVE)
  1928. 10206 #define TIMEOUT        32000    /* controller timeout in ms */
  1929. 10207 #define RECOVERYTIME     500    /* controller recovery time in ms */
  1930. 10208 #define INITIALIZED     0x01    /* drive is initialized */
  1931. 10209 #define DEAF            0x02    /* controller must be reset */
  1932. 10210 #define SMART           0x04    /* drive supports ATA commands */
  1933. 10211
  1934. 10212
  1935. 10213 /* Variables. */
  1936. 10214 PRIVATE struct wini {           /* main drive struct, one entry per drive */
  1937. 10215   unsigned state;               /* drive state: deaf, initialized, dead */
  1938. 10216   unsigned base;                /* base register of the register file */
  1939. 10217   unsigned irq;                 /* interrupt request line */
  1940. 10218   unsigned lcylinders;          /* logical number of cylinders (BIOS) */
  1941. 10219   unsigned lheads;              /* logical number of heads */
  1942. 10220   unsigned lsectors;            /* logical number of sectors per track */
  1943. 10221   unsigned pcylinders;          /* physical number of cylinders (translated) */
  1944. 10222   unsigned pheads;              /* physical number of heads */
  1945. 10223   unsigned psectors;            /* physical number of sectors per track */
  1946. 10224   unsigned ldhpref;             /* top four bytes of the LDH (head) register */
  1947. 10225   unsigned precomp;             /* write precompensation cylinder / 4 */
  1948. 10226   unsigned max_count;           /* max request for this drive */
  1949. 10227   unsigned open_ct;             /* in-use count */
  1950. 10228   struct device part[DEV_PER_DRIVE];    /* primary partitions: hd[0-4] */
  1951. 10229   struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
  1952. 10230 } wini[MAX_DRIVES], *w_wn;
  1953. 10231
  1954. 10232 PRIVATE struct trans {
  1955. 10233   struct iorequest_s *iop;      /* belongs to this I/O request */
  1956. 10234   unsigned long block;          /* first sector to transfer */
  1957. 10235   unsigned count;               /* byte count */
  1958. 10236   phys_bytes phys;              /* user physical address */
  1959. 10237 } wtrans[NR_IOREQS];
  1960. 10238
  1961. 10239 PRIVATE struct trans *w_tp;             /* to add transfer requests */
  1962. 10240 PRIVATE unsigned w_count;               /* number of bytes to transfer */
  1963. 10241 PRIVATE unsigned long w_nextblock;      /* next block on disk to transfer */
  1964. 10242 PRIVATE int w_opcode;                   /* DEV_READ or DEV_WRITE */
  1965. 10243 PRIVATE int w_command;                  /* current command in execution */
  1966. 10244 PRIVATE int w_status;                   /* status after interrupt */
  1967. 10245 PRIVATE int w_drive;                    /* selected drive */
  1968. 10246 PRIVATE struct device *w_dv;            /* device's base and size */
  1969. 10247
  1970. 10248 FORWARD _PROTOTYPE( void init_params, (void) );
  1971. 10249 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
  1972. 10250 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
  1973. 10251 FORWARD _PROTOTYPE( int w_identify, (void) );
  1974. 10252 FORWARD _PROTOTYPE( char *w_name, (void) );
  1975. 10253 FORWARD _PROTOTYPE( int w_specify, (void) );
  1976. 10254 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
  1977. 10255 FORWARD _PROTOTYPE( int w_finish, (void) );
  1978. 10256 FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
  1979. 10257 FORWARD _PROTOTYPE( void w_need_reset, (void) );
  1980. 10258 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
  1981. 10259 FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
  1982. 10260 FORWARD _PROTOTYPE( void w_timeout, (void) );
  1983. 10261 FORWARD _PROTOTYPE( int w_reset, (void) );
  1984. 10262 FORWARD _PROTOTYPE( int w_intr_wait, (void) );
  1985. 10263 FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
  1986. 10264 FORWARD _PROTOTYPE( int w_handler, (int irq) );
  1987. 10265 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
  1988. 10266
  1989. 10267 /* w_waitfor loop unrolled once for speed. */
  1990. 10268 #define waitfor(mask, value)    
  1991. 10269         ((in_byte(w_wn->base + REG_STATUS) & mask) == value 
  1992. 10270                 || w_waitfor(mask, value))
  1993. 10271
  1994. 10272
  1995. 10273 /* Entry points to this driver. */
  1996. 10274 PRIVATE struct driver w_dtab = {
  1997. 10275   w_name,               /* current device's name */
  1998. 10276   w_do_open,            /* open or mount request, initialize device */
  1999. 10277   w_do_close,           /* release device */
  2000. 10278   do_diocntl,           /* get or set a partition's geometry */
  2001. 10279   w_prepare,            /* prepare for I/O on a given minor device */
  2002. 10280   w_schedule,           /* precompute cylinder, head, sector, etc. */
  2003. 10281   w_finish,             /* do the I/O */
  2004. 10282   nop_cleanup,          /* nothing to clean up */
  2005. 10283   w_geometry,           /* tell the geometry of the disk */
  2006. 10284 };
  2007. 10285
  2008. 10286 #if ENABLE_ATAPI
  2009. 10287 #include "atapi.c"      /* extra code for ATAPI CD-ROM */
  2010. 10288 #endif
  2011. 10289
  2012. 10290
  2013. 10291 /*===========================================================================*
  2014. 10292  *                              at_winchester_task                           *
  2015. 10293  *===========================================================================*/
  2016. 10294 PUBLIC void at_winchester_task()
  2017. 10295 {
  2018. 10296 /* Set special disk parameters then call the generic main loop. */
  2019. 10297
  2020. 10298   init_params();
  2021. 10299
  2022. 10300   driver_task(&w_dtab);
  2023. 10301 }
  2024. 10304 /*============================================================================*
  2025. 10305  *                              init_params                                   *
  2026. 10306  *============================================================================*/
  2027. 10307 PRIVATE void init_params()
  2028. 10308 {
  2029. 10309 /* This routine is called at startup to initialize the drive parameters. */
  2030. 10310
  2031. 10311   u16_t parv[2];
  2032. 10312   unsigned int vector;
  2033. 10313   int drive, nr_drives, i;
  2034. 10314   struct wini *wn;
  2035. 10315   u8_t params[16];
  2036. 10316   phys_bytes param_phys = vir2phys(params);
  2037. 10317
  2038. 10318   /* Get the number of drives from the BIOS data area */
  2039. 10319   phys_copy(0x475L, param_phys, 1L);
  2040. 10320   if ((nr_drives = params[0]) > 2) nr_drives = 2;
  2041. 10321
  2042. 10322   for (drive = 0, wn = wini; drive < MAX_DRIVES; drive++, wn++) {
  2043. 10323         if (drive < nr_drives) {
  2044. 10324                 /* Copy the BIOS parameter vector */
  2045. 10325                 vector = drive == 0 ? WINI_0_PARM_VEC : WINI_1_PARM_VEC;
  2046. 10326                 phys_copy(vector * 4L, vir2phys(parv), 4L);
  2047. 10327
  2048. 10328                 /* Calculate the address of the parameters and copy them */
  2049. 10329                 phys_copy(hclick_to_physb(parv[1]) + parv[0], param_phys, 16L);
  2050. 10330
  2051. 10331                 /* Copy the parameters to the structures of the drive */
  2052. 10332                 wn->lcylinders = bp_cylinders(params);
  2053. 10333                 wn->lheads = bp_heads(params);
  2054. 10334                 wn->lsectors = bp_sectors(params);
  2055. 10335                 wn->precomp = bp_precomp(params) >> 2;
  2056. 10336         }
  2057. 10337         wn->ldhpref = ldh_init(drive);
  2058. 10338         wn->max_count = MAX_SECS << SECTOR_SHIFT;
  2059. 10339         if (drive < 2) {
  2060. 10340                 /* Controller 0. */
  2061. 10341                 wn->base = REG_BASE0;
  2062. 10342                 wn->irq = AT_IRQ0;
  2063. 10343         } else {
  2064. 10344                 /* Controller 1. */
  2065. 10345                 wn->base = REG_BASE1;
  2066. 10346                 wn->irq = AT_IRQ1;
  2067. 10347         }
  2068. 10348   }
  2069. 10349 }
  2070. 10352 /*============================================================================*
  2071. 10353  *                              w_do_open                                     *
  2072. 10354  *============================================================================*/
  2073. 10355 PRIVATE int w_do_open(dp, m_ptr)
  2074. 10356 struct driver *dp;
  2075. 10357 message *m_ptr;
  2076. 10358 {
  2077. 10359 /* Device open: Initialize the controller and read the partition table. */
  2078. 10360
  2079. 10361   int r;
  2080. 10362   struct wini *wn;
  2081. 10363   struct command cmd;
  2082. 10364
  2083. 10365   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  2084. 10366   wn = w_wn;
  2085. 10367
  2086. 10368   if (wn->state == 0) {
  2087. 10369         /* Try to identify the device. */
  2088. 10370         if (w_identify() != OK) {
  2089. 10371                 printf("%s: probe failedn", w_name());
  2090. 10372                 if (wn->state & DEAF) w_reset();
  2091. 10373                 wn->state = 0;
  2092. 10374                 return(ENXIO);
  2093. 10375         }
  2094. 10376   }
  2095. 10377   if (wn->open_ct++ == 0) {
  2096. 10378         /* Partition the disk. */
  2097. 10379         partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
  2098. 10380   }
  2099. 10381   return(OK);
  2100. 10382 }
  2101. 10385 /*===========================================================================*
  2102. 10386  *                              w_prepare                                    *
  2103. 10387  *===========================================================================*/
  2104. 10388 PRIVATE struct device *w_prepare(device)
  2105. 10389 int device;
  2106. 10390 {
  2107. 10391 /* Prepare for I/O on a device. */
  2108. 10392
  2109. 10393   /* Nothing to transfer as yet. */
  2110. 10394   w_count = 0;
  2111. 10395
  2112. 10396   if (device < NR_DEVICES) {                    /* hd0, hd1, ... */
  2113. 10397         w_drive = device / DEV_PER_DRIVE;       /* save drive number */
  2114. 10398         w_wn = &wini[w_drive];
  2115. 10399         w_dv = &w_wn->part[device % DEV_PER_DRIVE];
  2116. 10400   } else
  2117. 10401   if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
  2118. 10402         w_drive = device / SUB_PER_DRIVE;
  2119. 10403         w_wn = &wini[w_drive];
  2120. 10404         w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
  2121. 10405   } else {
  2122. 10406         return(NIL_DEV);
  2123. 10407   }
  2124. 10408   return(w_dv);
  2125. 10409 }
  2126. 10412 /*===========================================================================*
  2127. 10413  *                              w_identify                                   *
  2128. 10414  *===========================================================================*/
  2129. 10415 PRIVATE int w_identify()
  2130. 10416 {
  2131. 10417 /* Find out if a device exists, if it is an old AT disk, or a newer ATA
  2132. 10418  * drive, a removable media device, etc.
  2133. 10419  */
  2134. 10420
  2135. 10421   struct wini *wn = w_wn;
  2136. 10422   struct command cmd;
  2137. 10423   char id_string[40];
  2138. 10424   int i, r;
  2139. 10425   unsigned long size;
  2140. 10426 #define id_byte(n)      (&tmp_buf[2 * (n)])
  2141. 10427 #define id_word(n)      (((u16_t) id_byte(n)[0] <<  0) 
  2142. 10428                         |((u16_t) id_byte(n)[1] <<  8))
  2143. 10429 #define id_longword(n)  (((u32_t) id_byte(n)[0] <<  0) 
  2144. 10430                         |((u32_t) id_byte(n)[1] <<  8) 
  2145. 10431                         |((u32_t) id_byte(n)[2] << 16) 
  2146. 10432                         |((u32_t) id_byte(n)[3] << 24))
  2147. 10433
  2148. 10434   /* Check if the one of the registers exists. */
  2149. 10435   r = in_byte(wn->base + REG_CYL_LO);
  2150. 10436   out_byte(wn->base + REG_CYL_LO, ~r);
  2151. 10437   if (in_byte(wn->base + REG_CYL_LO) == r) return(ERR);
  2152. 10438
  2153. 10439   /* Looks OK; register IRQ and try an ATA identify command. */
  2154. 10440   put_irq_handler(wn->irq, w_handler);
  2155. 10441   enable_irq(wn->irq);
  2156. 10442
  2157. 10443   cmd.ldh     = wn->ldhpref;
  2158. 10444   cmd.command = ATA_IDENTIFY;
  2159. 10445   if (com_simple(&cmd) == OK) {
  2160. 10446         /* This is an ATA device. */
  2161. 10447         wn->state |= SMART;
  2162. 10448
  2163. 10449         /* Device information. */
  2164. 10450         port_read(wn->base + REG_DATA, tmp_phys, SECTOR_SIZE);
  2165. 10451
  2166. 10452         /* Why are the strings byte swapped??? */
  2167. 10453         for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
  2168. 10454
  2169. 10455         /* Preferred CHS translation mode. */
  2170. 10456         wn->pcylinders = id_word(1);
  2171. 10457         wn->pheads = id_word(3);
  2172. 10458         wn->psectors = id_word(6);
  2173. 10459         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
  2174. 10460
  2175. 10461         if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
  2176. 10462                 /* Drive is LBA capable and is big enough to trust it to
  2177. 10463                  * not make a mess of it.
  2178. 10464                  */
  2179. 10465                 wn->ldhpref |= LDH_LBA;
  2180. 10466                 size = id_longword(60);
  2181. 10467         }
  2182. 10468
  2183. 10469         if (wn->lcylinders == 0) {
  2184. 10470                 /* No BIOS parameters?  Then make some up. */
  2185. 10471                 wn->lcylinders = wn->pcylinders;
  2186. 10472                 wn->lheads = wn->pheads;
  2187. 10473                 wn->lsectors = wn->psectors;
  2188. 10474                 while (wn->lcylinders > 1024) {
  2189. 10475                         wn->lheads *= 2;
  2190. 10476                         wn->lcylinders /= 2;
  2191. 10477                 }
  2192. 10478         }
  2193. 10479   } else {
  2194. 10480         /* Not an ATA device; no translations, no special features.  Don't
  2195. 10481          * touch it unless the BIOS knows about it.
  2196. 10482          */
  2197. 10483         if (wn->lcylinders == 0) return(ERR);   /* no BIOS parameters */
  2198. 10484         wn->pcylinders = wn->lcylinders;
  2199. 10485         wn->pheads = wn->lheads;
  2200. 10486         wn->psectors = wn->lsectors;
  2201. 10487         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
  2202. 10488   }
  2203. 10489   /* The fun ends at 4 GB. */
  2204. 10490   if (size > ((u32_t) -1) / SECTOR_SIZE) size = ((u32_t) -1) / SECTOR_SIZE;
  2205. 10491
  2206. 10492   /* Base and size of the whole drive */
  2207. 10493   wn->part[0].dv_base = 0;
  2208. 10494   wn->part[0].dv_size = size << SECTOR_SHIFT;
  2209. 10495
  2210. 10496   if (w_specify() != OK && w_specify() != OK) return(ERR);
  2211. 10497
  2212. 10498   printf("%s: ", w_name());
  2213. 10499   if (wn->state & SMART) {
  2214. 10500         printf("%.40sn", id_string);
  2215. 10501   } else {
  2216. 10502         printf("%ux%ux%un", wn->pcylinders, wn->pheads, wn->psectors);
  2217. 10503   }
  2218. 10504   return(OK);
  2219. 10505 }
  2220. 10508 /*===========================================================================*
  2221. 10509  *                              w_name                                       *
  2222. 10510  *===========================================================================*/
  2223. 10511 PRIVATE char *w_name()
  2224. 10512 {
  2225. 10513 /* Return a name for the current device. */
  2226. 10514   static char name[] = "at-hd15";
  2227. 10515   unsigned device = w_drive * DEV_PER_DRIVE;
  2228. 10516
  2229. 10517   if (device < 10) {
  2230. 10518         name[5] = '0' + device;
  2231. 10519         name[6] = 0;
  2232. 10520   } else {
  2233. 10521         name[5] = '0' + device / 10;
  2234. 10522         name[6] = '0' + device % 10;
  2235. 10523   }
  2236. 10524   return name;
  2237. 10525 }
  2238. 10528 /*===========================================================================*
  2239. 10529  *                              w_specify                                    *
  2240. 10530  *===========================================================================*/
  2241. 10531 PRIVATE int w_specify()
  2242. 10532 {
  2243. 10533 /* Routine to initialize the drive after boot or when a reset is needed. */
  2244. 10534
  2245. 10535   struct wini *wn = w_wn;
  2246. 10536   struct command cmd;
  2247. 10537
  2248. 10538   if ((wn->state & DEAF) && w_reset() != OK) return(ERR);
  2249. 10539
  2250. 10540   /* Specify parameters: precompensation, number of heads and sectors. */
  2251. 10541   cmd.precomp = wn->precomp;
  2252. 10542   cmd.count   = wn->psectors;
  2253. 10543   cmd.ldh     = w_wn->ldhpref | (wn->pheads - 1);
  2254. 10544   cmd.command = CMD_SPECIFY;            /* Specify some parameters */
  2255. 10545
  2256. 10546   if (com_simple(&cmd) != OK) return(ERR);
  2257. 10547
  2258. 10548   if (!(wn->state & SMART)) {
  2259. 10549         /* Calibrate an old disk. */
  2260. 10550         cmd.sector  = 0;
  2261. 10551         cmd.cyl_lo  = 0;
  2262. 10552         cmd.cyl_hi  = 0;
  2263. 10553         cmd.ldh     = w_wn->ldhpref;
  2264. 10554         cmd.command = CMD_RECALIBRATE;
  2265. 10555
  2266. 10556         if (com_simple(&cmd) != OK) return(ERR);
  2267. 10557   }
  2268. 10558
  2269. 10559   wn->state |= INITIALIZED;
  2270. 10560   return(OK);
  2271. 10561 }
  2272. 10564 /*===========================================================================*
  2273. 10565  *                              w_schedule                                   *
  2274. 10566  *===========================================================================*/
  2275. 10567 PRIVATE int w_schedule(proc_nr, iop)
  2276. 10568 int proc_nr;                    /* process doing the request */
  2277. 10569 struct iorequest_s *iop;        /* pointer to read or write request */
  2278. 10570 {
  2279. 10571 /* Gather I/O requests on consecutive blocks so they may be read/written
  2280. 10572  * in one controller command.  (There is enough time to compute the next
  2281. 10573  * consecutive request while an unwanted block passes by.)
  2282. 10574  */
  2283. 10575   struct wini *wn = w_wn;
  2284. 10576   int r, opcode;
  2285. 10577   unsigned long pos;
  2286. 10578   unsigned nbytes, count;
  2287. 10579   unsigned long block;
  2288. 10580   phys_bytes user_phys;
  2289. 10581
  2290. 10582   /* This many bytes to read/write */
  2291. 10583   nbytes = iop->io_nbytes;
  2292. 10584   if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
  2293. 10585
  2294. 10586   /* From/to this position on the device */
  2295. 10587   pos = iop->io_position;
  2296. 10588   if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
  2297. 10589
  2298. 10590   /* To/from this user address */
  2299. 10591   user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
  2300. 10592   if (user_phys == 0) return(iop->io_nbytes = EINVAL);
  2301. 10593
  2302. 10594   /* Read or write? */
  2303. 10595   opcode = iop->io_request & ~OPTIONAL_IO;
  2304. 10596
  2305. 10597   /* Which block on disk and how close to EOF? */
  2306. 10598   if (pos >= w_dv->dv_size) return(OK);         /* At EOF */
  2307. 10599   if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
  2308. 10600   block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
  2309. 10601
  2310. 10602   if (w_count > 0 && block != w_nextblock) {
  2311. 10603         /* This new request can't be chained to the job being built */
  2312. 10604         if ((r = w_finish()) != OK) return(r);
  2313. 10605   }
  2314. 10606
  2315. 10607   /* The next consecutive block */
  2316. 10608   w_nextblock = block + (nbytes >> SECTOR_SHIFT);
  2317. 10609
  2318. 10610   /* While there are "unscheduled" bytes in the request: */
  2319. 10611   do {
  2320. 10612         count = nbytes;
  2321. 10613
  2322. 10614         if (w_count == wn->max_count) {
  2323. 10615                 /* The drive can't do more then max_count at once */
  2324. 10616                 if ((r = w_finish()) != OK) return(r);
  2325. 10617         }
  2326. 10618
  2327. 10619         if (w_count + count > wn->max_count)
  2328. 10620                 count = wn->max_count - w_count;
  2329. 10621
  2330. 10622         if (w_count == 0) {
  2331. 10623                 /* The first request in a row, initialize. */
  2332. 10624                 w_opcode = opcode;
  2333. 10625                 w_tp = wtrans;
  2334. 10626         }
  2335. 10627
  2336. 10628         /* Store I/O parameters */
  2337. 10629         w_tp->iop = iop;
  2338. 10630         w_tp->block = block;
  2339. 10631         w_tp->count = count;
  2340. 10632         w_tp->phys = user_phys;
  2341. 10633
  2342. 10634         /* Update counters */
  2343. 10635         w_tp++;
  2344. 10636         w_count += count;
  2345. 10637         block += count >> SECTOR_SHIFT;
  2346. 10638         user_phys += count;
  2347. 10639         nbytes -= count;
  2348. 10640   } while (nbytes > 0);
  2349. 10641
  2350. 10642   return(OK);
  2351. 10643 }
  2352. 10646 /*===========================================================================*
  2353. 10647  *                              w_finish                                     *
  2354. 10648  *===========================================================================*/
  2355. 10649 PRIVATE int w_finish()
  2356. 10650 {
  2357. 10651 /* Carry out the I/O requests gathered in wtrans[]. */
  2358. 10652
  2359. 10653   struct trans *tp = wtrans;
  2360. 10654   struct wini *wn = w_wn;
  2361. 10655   int r, errors;
  2362. 10656   struct command cmd;
  2363. 10657   unsigned cylinder, head, sector, secspcyl;
  2364. 10658
  2365. 10659   if (w_count == 0) return(OK); /* Spurious finish. */
  2366. 10660
  2367. 10661   r = ERR;      /* Trigger the first com_out */
  2368. 10662   errors = 0;
  2369. 10663
  2370. 10664   do {
  2371. 10665         if (r != OK) {
  2372. 10666                 /* The controller must be (re)programmed. */
  2373. 10667
  2374. 10668                 /* First check to see if a reinitialization is needed. */
  2375. 10669                 if (!(wn->state & INITIALIZED) && w_specify() != OK)
  2376. 10670                         return(tp->iop->io_nbytes = EIO);
  2377. 10671
  2378. 10672                 /* Tell the controller to transfer w_count bytes */
  2379. 10673                 cmd.precomp = wn->precomp;
  2380. 10674                 cmd.count   = (w_count >> SECTOR_SHIFT) & BYTE;
  2381. 10675                 if (wn->ldhpref & LDH_LBA) {
  2382. 10676                         cmd.sector  = (tp->block >>  0) & 0xFF;
  2383. 10677                         cmd.cyl_lo  = (tp->block >>  8) & 0xFF;
  2384. 10678                         cmd.cyl_hi  = (tp->block >> 16) & 0xFF;
  2385. 10679                         cmd.ldh     = wn->ldhpref | ((tp->block >> 24) & 0xF);
  2386. 10680                 } else {
  2387. 10681                         secspcyl = wn->pheads * wn->psectors;
  2388. 10682                         cylinder = tp->block / secspcyl;
  2389. 10683                         head = (tp->block % secspcyl) / wn->psectors;
  2390. 10684                         sector = tp->block % wn->psectors;
  2391. 10685                         cmd.sector  = sector + 1;
  2392. 10686                         cmd.cyl_lo  = cylinder & BYTE;
  2393. 10687                         cmd.cyl_hi  = (cylinder >> 8) & BYTE;
  2394. 10688                         cmd.ldh     = wn->ldhpref | head;
  2395. 10689                 }
  2396. 10690                 cmd.command = w_opcode == DEV_WRITE ? CMD_WRITE : CMD_READ;
  2397. 10691
  2398. 10692                 if ((r = com_out(&cmd)) != OK) {
  2399. 10693                         if (++errors == MAX_ERRORS) {
  2400. 10694                                 w_command = CMD_IDLE;
  2401. 10695                                 return(tp->iop->io_nbytes = EIO);
  2402. 10696                         }
  2403. 10697                         continue;       /* Retry */
  2404. 10698                 }
  2405. 10699         }
  2406. 10700
  2407. 10701         /* For each sector, wait for an interrupt and fetch the data (read),
  2408. 10702          * or supply data to the controller and wait for an interrupt (write).
  2409. 10703          */
  2410. 10704
  2411. 10705         if (w_opcode == DEV_READ) {
  2412. 10706                 if ((r = w_intr_wait()) == OK) {
  2413. 10707                         /* Copy data from the device's buffer to user space. */
  2414. 10708
  2415. 10709                         port_read(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
  2416. 10710
  2417. 10711                         tp->phys += SECTOR_SIZE;
  2418. 10712                         tp->iop->io_nbytes -= SECTOR_SIZE;
  2419. 10713                         w_count -= SECTOR_SIZE;
  2420. 10714                         if ((tp->count -= SECTOR_SIZE) == 0) tp++;
  2421. 10715                 } else {
  2422. 10716                         /* Any faulty data? */
  2423. 10717                         if (w_status & STATUS_DRQ) {
  2424. 10718                                 port_read(wn->base + REG_DATA, tmp_phys,
  2425. 10719                                                                 SECTOR_SIZE);
  2426. 10720                         }
  2427. 10721                 }
  2428. 10722         } else {
  2429. 10723                 /* Wait for data requested. */
  2430. 10724                 if (!waitfor(STATUS_DRQ, STATUS_DRQ)) {
  2431. 10725                         r = ERR;
  2432. 10726                 } else {
  2433. 10727                         /* Fill the buffer of the drive. */
  2434. 10728
  2435. 10729                         port_write(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
  2436. 10730                         r = w_intr_wait();
  2437. 10731                 }
  2438. 10732
  2439. 10733                 if (r == OK) {
  2440. 10734                         /* Book the bytes successfully written. */
  2441. 10735
  2442. 10736                         tp->phys += SECTOR_SIZE;
  2443. 10737                         tp->iop->io_nbytes -= SECTOR_SIZE;
  2444. 10738                         w_count -= SECTOR_SIZE;
  2445. 10739                         if ((tp->count -= SECTOR_SIZE) == 0) tp++;
  2446. 10740                 }
  2447. 10741         }
  2448. 10742
  2449. 10743         if (r != OK) {
  2450. 10744                 /* Don't retry if sector marked bad or too many errors */
  2451. 10745                 if (r == ERR_BAD_SECTOR || ++errors == MAX_ERRORS) {
  2452. 10746                         w_command = CMD_IDLE;
  2453. 10747                         return(tp->iop->io_nbytes = EIO);
  2454. 10748                 }
  2455. 10749
  2456. 10750                 /* Reset if halfway, but bail out if optional I/O. */
  2457. 10751                 if (errors == MAX_ERRORS / 2) {
  2458. 10752                         w_need_reset();
  2459. 10753                         if (tp->iop->io_request & OPTIONAL_IO) {
  2460. 10754                                 w_command = CMD_IDLE;
  2461. 10755                                 return(tp->iop->io_nbytes = EIO);
  2462. 10756                         }
  2463. 10757                 }
  2464. 10758                 continue;       /* Retry */
  2465. 10759         }
  2466. 10760         errors = 0;
  2467. 10761   } while (w_count > 0);
  2468. 10762
  2469. 10763   w_command = CMD_IDLE;
  2470. 10764   return(OK);
  2471. 10765 }
  2472. 10768 /*============================================================================*
  2473. 10769  *                              com_out                                       *
  2474. 10770  *============================================================================*/
  2475. 10771 PRIVATE int com_out(cmd)
  2476. 10772 struct command *cmd;            /* Command block */
  2477. 10773 {
  2478. 10774 /* Output the command block to the winchester controller and return status */
  2479. 10775
  2480. 10776   struct wini *wn = w_wn;
  2481. 10777   unsigned base = wn->base;
  2482. 10778
  2483. 10779   if (!waitfor(STATUS_BSY, 0)) {
  2484. 10780         printf("%s: controller not readyn", w_name());
  2485. 10781         return(ERR);
  2486. 10782   }
  2487. 10783
  2488. 10784   /* Select drive. */
  2489. 10785   out_byte(base + REG_LDH, cmd->ldh);
  2490. 10786
  2491. 10787   if (!waitfor(STATUS_BSY, 0)) {
  2492. 10788         printf("%s: drive not readyn", w_name());
  2493. 10789         return(ERR);
  2494. 10790   }
  2495. 10791
  2496. 10792   /* Schedule a wakeup call, some controllers are flaky. */
  2497. 10793   clock_mess(WAKEUP, w_timeout);
  2498. 10794
  2499. 10795   out_byte(base + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
  2500. 10796   out_byte(base + REG_PRECOMP, cmd->precomp);
  2501. 10797   out_byte(base + REG_COUNT, cmd->count);
  2502. 10798   out_byte(base + REG_SECTOR, cmd->sector);
  2503. 10799   out_byte(base + REG_CYL_LO, cmd->cyl_lo);
  2504. 10800   out_byte(base + REG_CYL_HI, cmd->cyl_hi);
  2505. 10801   lock();
  2506. 10802   out_byte(base + REG_COMMAND, cmd->command);
  2507. 10803   w_command = cmd->command;
  2508. 10804   w_status = STATUS_BSY;
  2509. 10805   unlock();
  2510. 10806   return(OK);
  2511. 10807 }
  2512. 10810 /*===========================================================================*
  2513. 10811  *                              w_need_reset                                 *
  2514. 10812  *===========================================================================*/
  2515. 10813 PRIVATE void w_need_reset()
  2516. 10814 {
  2517. 10815 /* The controller needs to be reset. */
  2518. 10816   struct wini *wn;
  2519. 10817
  2520. 10818   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
  2521. 10819         wn->state |= DEAF;
  2522. 10820         wn->state &= ~INITIALIZED;
  2523. 10821   }
  2524. 10822 }
  2525. 10825 /*============================================================================*
  2526. 10826  *                              w_do_close                                    *
  2527. 10827  *============================================================================*/
  2528. 10828 PRIVATE int w_do_close(dp, m_ptr)
  2529. 10829 struct driver *dp;
  2530. 10830 message *m_ptr;
  2531. 10831 {
  2532. 10832 /* Device close: Release a device. */
  2533. 10833
  2534. 10834   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  2535. 10835   w_wn->open_ct--;
  2536. 10836   return(OK);
  2537. 10837 }
  2538. 10840 /*============================================================================*
  2539. 10841  *                              com_simple                                    *
  2540. 10842  *============================================================================*/
  2541. 10843 PRIVATE int com_simple(cmd)
  2542. 10844 struct command *cmd;            /* Command block */
  2543. 10845 {
  2544. 10846 /* A simple controller command, only one interrupt and no data-out phase. */
  2545. 10847   int r;
  2546. 10848
  2547. 10849   if ((r = com_out(cmd)) == OK) r = w_intr_wait();
  2548. 10850   w_command = CMD_IDLE;
  2549. 10851   return(r);
  2550. 10852 }
  2551. 10855 /*===========================================================================*
  2552. 10856  *                              w_timeout                                    *
  2553. 10857  *===========================================================================*/
  2554. 10858 PRIVATE void w_timeout()
  2555. 10859 {
  2556. 10860   struct wini *wn = w_wn;
  2557. 10861
  2558. 10862   switch (w_command) {
  2559. 10863   case CMD_IDLE:
  2560. 10864         break;          /* fine */
  2561. 10865   case CMD_READ:
  2562. 10866   case CMD_WRITE:
  2563. 10867         /* Impossible, but not on PC's:  The controller does not respond. */
  2564. 10868
  2565. 10869         /* Limiting multisector I/O seems to help. */
  2566. 10870         if (wn->max_count > 8 * SECTOR_SIZE) {
  2567. 10871                 wn->max_count = 8 * SECTOR_SIZE;
  2568. 10872         } else {
  2569. 10873                 wn->max_count = SECTOR_SIZE;
  2570. 10874         }
  2571. 10875         /*FALL THROUGH*/
  2572. 10876   default:
  2573. 10877         /* Some other command. */
  2574. 10878         printf("%s: timeout on command %02xn", w_name(), w_command);
  2575. 10879         w_need_reset();
  2576. 10880         w_status = 0;
  2577. 10881         interrupt(WINCHESTER);
  2578. 10882   }
  2579. 10883 }
  2580. 10886 /*===========================================================================*
  2581. 10887  *                              w_reset                                      *
  2582. 10888  *===========================================================================*/
  2583. 10889 PRIVATE int w_reset()
  2584. 10890 {
  2585. 10891 /* Issue a reset to the controller.  This is done after any catastrophe,
  2586. 10892  * like the controller refusing to respond.
  2587. 10893  */
  2588. 10894
  2589. 10895   struct wini *wn;
  2590. 10896   int err;
  2591. 10897
  2592. 10898   /* Wait for any internal drive recovery. */
  2593. 10899   milli_delay(RECOVERYTIME);
  2594. 10900
  2595. 10901   /* Strobe reset bit */
  2596. 10902   out_byte(w_wn->base + REG_CTL, CTL_RESET);
  2597. 10903   milli_delay(1);
  2598. 10904   out_byte(w_wn->base + REG_CTL, 0);
  2599. 10905   milli_delay(1);
  2600. 10906
  2601. 10907   /* Wait for controller ready */
  2602. 10908   if (!w_waitfor(STATUS_BSY | STATUS_RDY, STATUS_RDY)) {
  2603. 10909         printf("%s: reset failed, drive busyn", w_name());
  2604. 10910         return(ERR);
  2605. 10911   }
  2606. 10912
  2607. 10913   /* The error register should be checked now, but some drives mess it up. */
  2608. 10914
  2609. 10915   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
  2610. 10916         if (wn->base == w_wn->base) wn->state &= ~DEAF;
  2611. 10917   }
  2612. 10918   return(OK);
  2613. 10919 }
  2614. 10922 /*============================================================================*
  2615. 10923  *                              w_intr_wait                                   *
  2616. 10924  *============================================================================*/
  2617. 10925 PRIVATE int w_intr_wait()
  2618. 10926 {
  2619. 10927 /* Wait for a task completion interrupt and return results. */
  2620. 10928
  2621. 10929   message mess;
  2622. 10930   int r;
  2623. 10931
  2624. 10932   /* Wait for an interrupt that sets w_status to "not busy". */
  2625. 10933   while (w_status & STATUS_BSY) receive(HARDWARE, &mess);
  2626. 10934
  2627. 10935   /* Check status. */
  2628. 10936   lock();
  2629. 10937   if ((w_status & (STATUS_BSY | STATUS_RDY | STATUS_WF | STATUS_ERR))
  2630. 10938                                                         == STATUS_RDY) {
  2631. 10939         r = OK;
  2632. 10940         w_status |= STATUS_BSY; /* assume still busy with I/O */
  2633. 10941   } else
  2634. 10942   if ((w_status & STATUS_ERR) && (in_byte(w_wn->base + REG_ERROR) & ERROR_BB)) {
  2635. 10943         r = ERR_BAD_SECTOR;     /* sector marked bad, retries won't help */
  2636. 10944   } else {
  2637. 10945         r = ERR;                /* any other error */
  2638. 10946   }
  2639. 10947   unlock();
  2640. 10948   return(r);
  2641. 10949 }
  2642. 10952 /*==========================================================================*
  2643. 10953  *                              w_waitfor                                   *
  2644. 10954  *==========================================================================*/
  2645. 10955 PRIVATE int w_waitfor(mask, value)
  2646. 10956 int mask;                       /* status mask */
  2647. 10957 int value;                      /* required status */
  2648. 10958 {
  2649. 10959 /* Wait until controller is in the required state.  Return zero on timeout. */
  2650. 10960
  2651. 10961   struct milli_state ms;
  2652. 10962
  2653. 10963   milli_start(&ms);
  2654. 10964   do {
  2655. 10965        if ((in_byte(w_wn->base + REG_STATUS) & mask) == value) return 1;
  2656. 10966   } while (milli_elapsed(&ms) < TIMEOUT);
  2657. 10967
  2658. 10968   w_need_reset();       /* Controller gone deaf. */
  2659. 10969   return(0);
  2660. 10970 }
  2661. 10973 /*==========================================================================*
  2662. 10974  *                              w_handler                                   *
  2663. 10975  *==========================================================================*/
  2664. 10976 PRIVATE int w_handler(irq)
  2665. 10977 int irq;
  2666. 10978 {
  2667. 10979 /* Disk interrupt, send message to winchester task and reenable interrupts. */
  2668. 10980
  2669. 10981   w_status = in_byte(w_wn->base + REG_STATUS);  /* acknowledge interrupt */
  2670. 10982   interrupt(WINCHESTER);
  2671. 10983   return 1;
  2672. 10984 }
  2673. 10987 /*============================================================================*
  2674. 10988  *                              w_geometry                                    *
  2675. 10989  *============================================================================*/
  2676. 10990 PRIVATE void w_geometry(entry)
  2677. 10991 struct partition *entry;
  2678. 10992 {
  2679. 10993   entry->cylinders = w_wn->lcylinders;
  2680. 10994   entry->heads = w_wn->lheads;
  2681. 10995   entry->sectors = w_wn->lsectors;
  2682. 10996 }
  2683. 10997 #endif /* ENABLE_AT_WINI */
  2684. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2685. src/kernel/clock.c    
  2686. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2687. 11000 /* This file contains the code and data for the clock task.  The clock task
  2688. 11001  * accepts six message types:
  2689. 11002  *
  2690. 11003  *   HARD_INT:    a clock interrupt has occurred
  2691. 11004  *   GET_UPTIME:  get the time since boot in ticks
  2692. 11005  *   GET_TIME:    a process wants the real time in seconds
  2693. 11006  *   SET_TIME:    a process wants to set the real time in seconds
  2694. 11007  *   SET_ALARM:   a process wants to be alerted after a specified interval
  2695. 11008  *   SET_SYN_AL:  set the sync alarm
  2696. 11009  *
  2697. 11010  *
  2698. 11011  * The input message is format m6.  The parameters are as follows:
  2699. 11012  *
  2700. 11013  *     m_type    CLOCK_PROC   FUNC    NEW_TIME
  2701. 11014  * ---------------------------------------------
  2702. 11015  * | HARD_INT   |          |         |         |
  2703. 11016  * |------------+----------+---------+---------|
  2704. 11017  * | GET_UPTIME |          |         |         |
  2705. 11018  * |------------+----------+---------+---------|
  2706. 11019  * | GET_TIME   |          |         |         |
  2707. 11020  * |------------+----------+---------+---------|
  2708. 11021  * | SET_TIME   |          |         | newtime |