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

操作系统开发

开发平台:

WINDOWS

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