00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "../drivers.h"
00024 #include "../libdriver/driver.h"
00025 #include "../libdriver/drvlib.h"
00026 #include <minix/sysutil.h>
00027 #include <minix/keymap.h>
00028 #include <sys/ioc_disk.h>
00029 #include <ibm/int86.h>
00030 #include <assert.h>
00031
00032 #define ME "BIOS_WINI"
00033
00034
00035 #define ERR (-1)
00036
00037
00038 #define MAX_DRIVES 8
00039 #define MAX_SECS 255
00040 #define NR_MINORS (MAX_DRIVES * DEV_PER_DRIVE)
00041 #define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
00042 #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
00043
00044 PRIVATE int pc_at = 1;
00045
00046
00047 PRIVATE struct wini {
00048 unsigned cylinders;
00049 unsigned heads;
00050 unsigned sectors;
00051 unsigned open_ct;
00052 int drive_id;
00053 int present;
00054 int int13ext;
00055 struct device part[DEV_PER_DRIVE];
00056 struct device subpart[SUB_PER_DRIVE];
00057 } wini[MAX_DRIVES], *w_wn;
00058
00059 PRIVATE int w_drive;
00060 PRIVATE struct device *w_dv;
00061 PRIVATE vir_bytes bios_buf_vir, bios_buf_size;
00062 PRIVATE phys_bytes bios_buf_phys;
00063 PRIVATE int remap_first = 0;
00064
00065 _PROTOTYPE(int main, (void) );
00066 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
00067 FORWARD _PROTOTYPE( char *w_name, (void) );
00068 FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position,
00069 iovec_t *iov, unsigned nr_req) );
00070 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
00071 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
00072 FORWARD _PROTOTYPE( void w_init, (void) );
00073 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry));
00074 FORWARD _PROTOTYPE( int w_other, (struct driver *dp, message *m_ptr) );
00075
00076
00077 PRIVATE struct driver w_dtab = {
00078 w_name,
00079 w_do_open,
00080 w_do_close,
00081 do_diocntl,
00082 w_prepare,
00083 w_transfer,
00084 nop_cleanup,
00085 w_geometry,
00086 nop_signal,
00087 nop_alarm,
00088 nop_cancel,
00089 nop_select,
00090 w_other,
00091 NULL
00092 };
00093
00094
00095
00096
00097 PUBLIC int main()
00098 {
00099 long v;
00100 struct sigaction sa;
00101
00102 sa.sa_handler = SIG_MESS;
00103 sigemptyset(&sa.sa_mask);
00104 sa.sa_flags = 0;
00105 if (sigaction(SIGTERM,&sa,NULL)<0) panic("BIOS","sigaction failed", errno);
00106
00107 v= 0;
00108 env_parse("bios_remap_first", "d", 0, &v, 0, 1);
00109 remap_first= v;
00110
00111
00112 driver_task(&w_dtab);
00113 return(OK);
00114 }
00115
00116
00117
00118
00119 PRIVATE struct device *w_prepare(device)
00120 int device;
00121 {
00122
00123
00124 if (device < NR_MINORS) {
00125 w_drive = device / DEV_PER_DRIVE;
00126 w_wn = &wini[w_drive];
00127 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
00128 } else
00129 if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {
00130 w_drive = device / SUB_PER_DRIVE;
00131 w_wn = &wini[w_drive];
00132 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
00133 } else {
00134 return(NIL_DEV);
00135 }
00136 if (w_drive >= MAX_DRIVES || !w_wn->present)
00137 return NIL_DEV;
00138 return(w_dv);
00139 }
00140
00141
00142
00143
00144 PRIVATE char *w_name()
00145 {
00146
00147 static char name[] = "bios-d0";
00148
00149 name[6] = '0' + w_drive;
00150 return name;
00151 }
00152
00153
00154
00155
00156 PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)
00157 int proc_nr;
00158 int opcode;
00159 off_t position;
00160 iovec_t *iov;
00161 unsigned nr_req;
00162 {
00163 struct wini *wn = w_wn;
00164 iovec_t *iop, *iov_end = iov + nr_req;
00165 int r, errors;
00166 unsigned nbytes, count, chunk;
00167 unsigned long block;
00168 vir_bytes i13e_rw_off, rem_buf_size;
00169 unsigned long dv_size = cv64ul(w_dv->dv_size);
00170 unsigned secspcyl = wn->heads * wn->sectors;
00171 struct int13ext_rw {
00172 u8_t len;
00173 u8_t res1;
00174 u16_t count;
00175 u16_t addr[2];
00176 u32_t block[2];
00177 } i13e_rw;
00178 struct reg86u reg86;
00179
00180
00181 if ((position & SECTOR_MASK) != 0) return(EINVAL);
00182
00183 errors = 0;
00184
00185 i13e_rw_off= bios_buf_size-sizeof(i13e_rw);
00186 rem_buf_size= (i13e_rw_off & ~SECTOR_MASK);
00187 assert(rem_buf_size != 0);
00188
00189 while (nr_req > 0) {
00190
00191 nbytes = 0;
00192 for (iop = iov; iop < iov_end; iop++) {
00193 if (nbytes + iop->iov_size > rem_buf_size) {
00194
00195 if (nbytes == 0) nbytes = rem_buf_size;
00196 break;
00197 }
00198 nbytes += iop->iov_size;
00199 }
00200 if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
00201
00202
00203 if (position >= dv_size) return(OK);
00204 if (position + nbytes > dv_size) nbytes = dv_size - position;
00205 block = div64u(add64ul(w_dv->dv_base, position), SECTOR_SIZE);
00206
00207
00208 if (errors > 0) nbytes = SECTOR_SIZE;
00209
00210 if (opcode == DEV_SCATTER) {
00211
00212 count = 0;
00213 for (iop = iov; count < nbytes; iop++) {
00214 chunk = iov->iov_size;
00215 if (count + chunk > nbytes) chunk = nbytes - count;
00216 assert(chunk <= rem_buf_size);
00217 r= sys_vircopy(proc_nr, D, iop->iov_addr,
00218 SYSTEM, D, bios_buf_vir+count,
00219 chunk);
00220 if (r != OK)
00221 panic(ME, "sys_vircopy failed", r);
00222 count += chunk;
00223 }
00224 }
00225
00226
00227 if (wn->int13ext) {
00228 i13e_rw.len = 0x10;
00229 i13e_rw.res1 = 0;
00230 i13e_rw.count = nbytes >> SECTOR_SHIFT;
00231 i13e_rw.addr[0] = bios_buf_phys % HCLICK_SIZE;
00232 i13e_rw.addr[1] = bios_buf_phys / HCLICK_SIZE;
00233 i13e_rw.block[0] = block;
00234 i13e_rw.block[1] = 0;
00235 r= sys_vircopy(SELF, D, (vir_bytes)&i13e_rw,
00236 SYSTEM, D, (bios_buf_vir+i13e_rw_off),
00237 sizeof(i13e_rw));
00238 if (r != OK)
00239 panic(ME, "sys_vircopy failed", r);
00240
00241
00242 reg86.u.b.intno = 0x13;
00243 reg86.u.w.ax = opcode == DEV_SCATTER ? 0x4300 : 0x4200;
00244 reg86.u.b.dl = wn->drive_id;
00245 reg86.u.w.si = (bios_buf_phys + i13e_rw_off) % HCLICK_SIZE;
00246 reg86.u.w.ds = (bios_buf_phys + i13e_rw_off) / HCLICK_SIZE;
00247 } else {
00248
00249 unsigned cylinder = block / secspcyl;
00250 unsigned sector = (block % wn->sectors) + 1;
00251 unsigned head = (block % secspcyl) / wn->sectors;
00252
00253 reg86.u.b.intno = 0x13;
00254 reg86.u.b.ah = opcode == DEV_SCATTER ? 0x03 : 0x02;
00255 reg86.u.b.al = nbytes >> SECTOR_SHIFT;
00256 reg86.u.w.bx = bios_buf_phys % HCLICK_SIZE;
00257 reg86.u.w.es = bios_buf_phys / HCLICK_SIZE;
00258 reg86.u.b.ch = cylinder & 0xFF;
00259 reg86.u.b.cl = sector | ((cylinder & 0x300) >> 2);
00260 reg86.u.b.dh = head;
00261 reg86.u.b.dl = wn->drive_id;
00262 }
00263
00264 r= sys_int86(®86);
00265 if (r != OK)
00266 panic(ME, "BIOS call failed", r);
00267
00268 if (reg86.u.w.f & 0x0001) {
00269
00270 if (++errors == 2) return(EIO);
00271 continue;
00272 }
00273
00274 if (opcode == DEV_GATHER) {
00275
00276 count = 0;
00277 for (iop = iov; count < nbytes; iop++) {
00278 chunk = iov->iov_size;
00279 if (count + chunk > nbytes) chunk = nbytes - count;
00280 assert(chunk <= rem_buf_size);
00281 r= sys_vircopy(SYSTEM, D, bios_buf_vir+count,
00282 proc_nr, D, iop->iov_addr,
00283 chunk);
00284 if (r != OK)
00285 panic(ME, "sys_vircopy failed", r);
00286 count += chunk;
00287 }
00288 }
00289
00290
00291 position += nbytes;
00292 for (;;) {
00293 if (nbytes < iov->iov_size) {
00294
00295 iov->iov_addr += nbytes;
00296 iov->iov_size -= nbytes;
00297 break;
00298 }
00299 nbytes -= iov->iov_size;
00300 iov->iov_addr += iov->iov_size;
00301 iov->iov_size = 0;
00302 if (nbytes == 0) {
00303
00304
00305
00306 return(OK);
00307 }
00308 iov++;
00309 nr_req--;
00310 }
00311 }
00312 return(OK);
00313 }
00314
00315
00316
00317
00318 PRIVATE int w_do_open(dp, m_ptr)
00319 struct driver *dp;
00320 message *m_ptr;
00321 {
00322
00323
00324 static int init_done = FALSE;
00325
00326 if (!init_done) { w_init(); init_done = TRUE; }
00327
00328 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
00329
00330 if (w_wn->open_ct++ == 0) {
00331
00332 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY, 0);
00333 }
00334 return(OK);
00335 }
00336
00337
00338
00339
00340 PRIVATE int w_do_close(dp, m_ptr)
00341 struct driver *dp;
00342 message *m_ptr;
00343 {
00344
00345
00346 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
00347 w_wn->open_ct--;
00348 return(OK);
00349 }
00350
00351
00352
00353
00354 PRIVATE void w_init()
00355 {
00356
00357
00358 int r, drive, drive_id, nr_drives;
00359 struct wini *wn;
00360 unsigned long capacity;
00361 struct int13ext_params {
00362 u16_t len;
00363 u16_t flags;
00364 u32_t cylinders;
00365 u32_t heads;
00366 u32_t sectors;
00367 u32_t capacity[2];
00368 u16_t bts_per_sec;
00369 u16_t config[2];
00370 } i13e_par;
00371 struct reg86u reg86;
00372
00373
00374 r= sys_getbiosbuffer(&bios_buf_vir, &bios_buf_size);
00375 if (r != OK)
00376 panic(ME, "sys_getbiosbuffer failed", r);
00377 r= sys_umap(SYSTEM, D, (vir_bytes)bios_buf_vir, (phys_bytes)bios_buf_size,
00378 &bios_buf_phys);
00379 if (r != OK)
00380 panic(ME, "sys_umap failed", r);
00381 if (bios_buf_phys+bios_buf_size > 0x100000)
00382 panic(ME, "bad BIOS buffer, phys", bios_buf_phys);
00383 #if 0
00384 printf("bios_wini: got buffer size %d, virtual 0x%x, phys 0x%x\n",
00385 bios_buf_size, bios_buf_vir, bios_buf_phys);
00386 #endif
00387
00388
00389 for (drive = 0; drive < MAX_DRIVES; drive++) {
00390 if (remap_first)
00391 {
00392 if (drive == 7)
00393 drive_id= 0x80;
00394 else
00395 drive_id= 0x80 + drive + 1;
00396 }
00397 else
00398 drive_id= 0x80 + drive;
00399
00400 (void) w_prepare(drive * DEV_PER_DRIVE);
00401 wn = w_wn;
00402 wn->drive_id= drive_id;
00403
00404 reg86.u.b.intno = 0x13;
00405 reg86.u.b.ah = 0x08;
00406 reg86.u.b.dl = drive_id;
00407 r= sys_int86(®86);
00408 if (r != OK)
00409 panic(ME, "BIOS call failed", r);
00410
00411 nr_drives = !(reg86.u.w.f & 0x0001) ? reg86.u.b.dl : drive;
00412 if (drive_id >= 0x80 + nr_drives) continue;
00413 wn->present= 1;
00414
00415 wn->heads = reg86.u.b.dh + 1;
00416 wn->sectors = reg86.u.b.cl & 0x3F;
00417 wn->cylinders = (reg86.u.b.ch | ((reg86.u.b.cl & 0xC0) << 2)) + 1;
00418
00419 capacity = (unsigned long) wn->cylinders * wn->heads * wn->sectors;
00420
00421 reg86.u.b.intno = 0x13;
00422 reg86.u.b.ah = 0x41;
00423 reg86.u.w.bx = 0x55AA;
00424 reg86.u.b.dl = drive_id;
00425
00426 if (pc_at) {
00427 r= sys_int86(®86);
00428 if (r != OK)
00429 panic(ME, "BIOS call failed", r);
00430 }
00431
00432 if (!(reg86.u.w.f & 0x0001) && reg86.u.w.bx == 0xAA55
00433 && (reg86.u.w.cx & 0x0001)) {
00434
00435 i13e_par.len = 0x001E;
00436 r= sys_vircopy(SELF, D, (vir_bytes)&i13e_par,
00437 SYSTEM, D, bios_buf_vir,
00438 sizeof(i13e_par));
00439 if (r != OK)
00440 panic(ME, "sys_vircopy failed\n", r);
00441 reg86.u.b.intno = 0x13;
00442 reg86.u.b.ah = 0x48;
00443 reg86.u.b.dl = drive_id;
00444 reg86.u.w.si = bios_buf_phys % HCLICK_SIZE;
00445 reg86.u.w.ds = bios_buf_phys / HCLICK_SIZE;
00446
00447 r= sys_int86(®86);
00448 if (r != OK)
00449 panic(ME, "BIOS call failed", r);
00450
00451 r= sys_vircopy(SYSTEM, D, bios_buf_vir,
00452 SELF, D, (vir_bytes)&i13e_par,
00453 sizeof(i13e_par));
00454 if (r != OK)
00455 panic(ME, "sys_vircopy failed\n", r);
00456
00457 if (!(reg86.u.w.f & 0x0001)) {
00458 wn->int13ext = 1;
00459 capacity = i13e_par.capacity[0];
00460 if (i13e_par.capacity[1] != 0) capacity = 0xFFFFFFFF;
00461 }
00462 }
00463
00464 if (wn->int13ext) {
00465 printf("%s: %lu sectors\n", w_name(), capacity);
00466 } else {
00467 printf("%s: %d cylinders, %d heads, %d sectors per track\n",
00468 w_name(), wn->cylinders, wn->heads, wn->sectors);
00469 }
00470 wn->part[0].dv_size = mul64u(capacity, SECTOR_SIZE);
00471 }
00472 }
00473
00474
00475
00476
00477 PRIVATE void w_geometry(entry)
00478 struct partition *entry;
00479 {
00480 entry->cylinders = w_wn->cylinders;
00481 entry->heads = w_wn->heads;
00482 entry->sectors = w_wn->sectors;
00483 }
00484
00485
00486
00487
00488 PRIVATE int w_other(dr, m)
00489 struct driver *dr;
00490 message *m;
00491 {
00492 int r, timeout, prev;
00493
00494 if (m->m_type != DEV_IOCTL ) {
00495 return EINVAL;
00496 }
00497
00498 if (m->REQUEST == DIOCOPENCT) {
00499 int count;
00500 if (w_prepare(m->DEVICE) == NIL_DEV) return ENXIO;
00501 count = w_wn->open_ct;
00502 if ((r=sys_datacopy(SELF, (vir_bytes)&count,
00503 m->IO_ENDPT, (vir_bytes)m->ADDRESS, sizeof(count))) != OK)
00504 return r;
00505 return OK;
00506 }
00507
00508 return EINVAL;
00509 }
00510