Home | History | Annotate | Line # | Download | only in libsa
      1  1.10    andvar /*	$NetBSD: winblk.c,v 1.10 2023/07/15 21:41:25 andvar Exp $	*/
      2   1.3  takemura 
      3   1.3  takemura /*-
      4   1.3  takemura  * Copyright (c) 1999 Shin Takemura.
      5   1.3  takemura  * All rights reserved.
      6   1.3  takemura  *
      7   1.3  takemura  * This software is part of the PocketBSD.
      8   1.3  takemura  *
      9   1.3  takemura  * Redistribution and use in source and binary forms, with or without
     10   1.3  takemura  * modification, are permitted provided that the following conditions
     11   1.3  takemura  * are met:
     12   1.3  takemura  * 1. Redistributions of source code must retain the above copyright
     13   1.3  takemura  *    notice, this list of conditions and the following disclaimer.
     14   1.3  takemura  * 2. Redistributions in binary form must reproduce the above copyright
     15   1.3  takemura  *    notice, this list of conditions and the following disclaimer in the
     16   1.3  takemura  *    documentation and/or other materials provided with the distribution.
     17   1.3  takemura  * 3. All advertising materials mentioning features or use of this software
     18   1.3  takemura  *    must display the following acknowledgement:
     19   1.3  takemura  *	This product includes software developed by the PocketBSD project
     20   1.3  takemura  *	and its contributors.
     21   1.3  takemura  * 4. Neither the name of the project nor the names of its contributors
     22   1.3  takemura  *    may be used to endorse or promote products derived from this software
     23   1.3  takemura  *    without specific prior written permission.
     24   1.3  takemura  *
     25   1.3  takemura  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26   1.3  takemura  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27   1.3  takemura  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28   1.3  takemura  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29   1.3  takemura  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30   1.3  takemura  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31   1.3  takemura  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32   1.3  takemura  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33   1.3  takemura  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34   1.3  takemura  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35   1.3  takemura  * SUCH DAMAGE.
     36   1.3  takemura  *
     37   1.3  takemura  */
     38   1.3  takemura #define STANDALONE_WINDOWS_SIDE
     39   1.3  takemura #include <stand.h>
     40   1.3  takemura #include <winblk.h>
     41   1.3  takemura #include <winioctl.h>
     42   1.3  takemura #include <sys/disklabel.h>
     43   1.4  takemura #include "diskio.h"
     44   1.3  takemura 
     45   1.3  takemura /*
     46   1.3  takemura  * BOOL
     47   1.3  takemura  * DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
     48   1.3  takemura  * 			LPVOID lpInBuffer, DWORD nInBufferSize,
     49   1.3  takemura  * 			LPVOID lpOutBuffer, DWORD nOutBufferSize,
     50   1.3  takemura  * 			LPDWORD lpBytesReturned,
     51   1.3  takemura  *			LPOVERLAPPED lpOverlapped);
     52   1.3  takemura  */
     53   1.3  takemura 
     54   1.3  takemura #ifdef DEBUG
     55   1.3  takemura #define DEBUG_PRINTF(a) win_printf a
     56   1.3  takemura #else
     57   1.3  takemura #define DEBUG_PRINTF(a)
     58   1.3  takemura #endif
     59   1.3  takemura 
     60   1.3  takemura #define islower(c)	('a' <= (c) && (c) <= 'z')
     61   1.3  takemura #define toupper(c)	(islower(c) ? ((c) - 'a' + 'A') : (c))
     62   1.3  takemura 
     63   1.3  takemura #define BLKSZ	512
     64   1.3  takemura 
     65   1.3  takemura struct winblk {
     66   1.3  takemura 	HANDLE	hDevice;
     67   1.3  takemura 	DISK_INFO di;
     68   1.5     lukem 	struct mbr_partition mbr[MBR_PART_COUNT];
     69   1.3  takemura 	struct disklabel dl;
     70   1.3  takemura 	char buf[BLKSZ];
     71   1.3  takemura 	int start;
     72   1.3  takemura };
     73   1.3  takemura 
     74   1.3  takemura static int rawread(struct winblk *ctx, int start, int nsecs, char *buf);
     75   1.3  takemura 
     76   1.3  takemura int
     77   1.8       dsl winblkstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize)
     78   1.3  takemura {
     79   1.3  takemura 	struct winblk *ctx = (struct winblk*)devdata;
     80   1.3  takemura 	int error;
     81   1.3  takemura 	size_t nblks;
     82   1.3  takemura 
     83   1.3  takemura 	if (flag != F_READ)
     84   1.3  takemura 		return (EROFS);
     85   1.3  takemura 
     86   1.3  takemura 	dblk += ctx->start;
     87   1.3  takemura 	nblks = (size / BLKSZ);
     88   1.3  takemura 
     89   1.3  takemura 	if (error = rawread(ctx, dblk, nblks, buf)) {
     90   1.3  takemura 		return (error);
     91   1.3  takemura 	}
     92   1.3  takemura 	if (nblks * BLKSZ < size) {
     93   1.3  takemura 		if (error = rawread(ctx, dblk + nblks, 1, ctx->buf)) {
     94   1.3  takemura 			return (error);
     95   1.3  takemura 		}
     96   1.3  takemura 		memcpy((BYTE*)buf + nblks * BLKSZ, ctx->buf,
     97   1.3  takemura 		       size - nblks * BLKSZ);
     98   1.3  takemura 	}
     99   1.3  takemura 
    100   1.3  takemura 	if (rsize)
    101   1.3  takemura 		*rsize = size;
    102   1.3  takemura 	return (0);
    103   1.3  takemura }
    104   1.3  takemura 
    105   1.3  takemura 
    106   1.3  takemura int
    107   1.3  takemura winblkopen(struct open_file *f, ...)
    108   1.3  takemura /* file, devname, unit, partition */
    109   1.3  takemura {
    110   1.3  takemura 	va_list ap;
    111   1.3  takemura 	struct winblk *ctx = NULL;
    112   1.3  takemura 	char *devname;
    113   1.3  takemura 	int unit;
    114   1.3  takemura 	int partition;
    115   1.3  takemura 	TCHAR wdevname[6];
    116   1.3  takemura 	DWORD wres;
    117   1.3  takemura 	int i;
    118   1.3  takemura 	int start_386bsd;
    119   1.3  takemura 
    120   1.3  takemura 	int error = 0;
    121   1.3  takemura 
    122   1.3  takemura 	ctx = (struct winblk *)alloc(sizeof(*ctx));
    123   1.3  takemura 	if (!ctx) {
    124   1.3  takemura 		error = ENOMEM;
    125   1.3  takemura 		goto end;
    126   1.3  takemura 	}
    127   1.3  takemura 	f->f_devdata = ctx;
    128   1.3  takemura 
    129   1.3  takemura 	va_start(ap, f);
    130   1.3  takemura 	devname = va_arg(ap, char*);
    131   1.3  takemura 	unit = va_arg(ap, int);
    132   1.3  takemura 	partition = va_arg(ap, int);
    133   1.3  takemura         va_end(ap);
    134   1.3  takemura 
    135   1.3  takemura 	/*
    136  1.10    andvar 	 *  Windows' device name must be 3 upper letters and 1 digit
    137   1.3  takemura 	 *  following a semicolon like "DSK1:".
    138   1.3  takemura 	 */
    139   1.3  takemura 	if (strlen(devname) != 3 || unit < 0 || 9 < unit) {
    140   1.3  takemura 		error = ENODEV;
    141   1.3  takemura 		goto end;
    142   1.3  takemura 	}
    143   1.3  takemura 	wsprintf(wdevname, TEXT("%C%C%C%d:"),
    144   1.3  takemura 		toupper(devname[0]),
    145   1.3  takemura 		toupper(devname[1]),
    146   1.3  takemura 		toupper(devname[2]),
    147   1.3  takemura 		unit);
    148   1.3  takemura 	DEBUG_PRINTF((TEXT("winblk.open: block device name is '%s'\n"),
    149   1.3  takemura 		      wdevname));
    150   1.3  takemura 
    151   1.3  takemura 	ctx->hDevice = CreateFile(wdevname, GENERIC_READ, 0, NULL,
    152   1.3  takemura 				  OPEN_EXISTING, 0, NULL);
    153   1.3  takemura 	if (ctx->hDevice == INVALID_HANDLE_VALUE) {
    154   1.3  takemura 		win_printf(TEXT("can't open %s.\n"), wdevname);
    155   1.3  takemura 		error = ENODEV; /* XXX, We shuld check GetLastError(). */
    156   1.3  takemura 		goto end;
    157   1.3  takemura 	}
    158   1.3  takemura 
    159   1.3  takemura 	/*
    160   1.3  takemura 	 *  get DISK_INFO
    161   1.3  takemura 	 *  CHS, sector size and device flags.
    162   1.3  takemura 	 */
    163   1.3  takemura 	if (!DeviceIoControl(ctx->hDevice, DISK_IOCTL_GETINFO,
    164   1.3  takemura 			     &ctx->di, sizeof(ctx->di),
    165   1.3  takemura 			     NULL, 0, &wres, NULL)) {
    166   1.3  takemura 		win_printf(TEXT("DeviceIoControl() failed.error=%d\n"),
    167   1.3  takemura 			   GetLastError());
    168   1.3  takemura 
    169   1.3  takemura 		error = EIO; /* XXX, We shuld check GetLastError(). */
    170   1.3  takemura 		goto end;
    171   1.3  takemura 	}
    172   1.3  takemura 
    173   1.3  takemura #ifdef DEBUG
    174   1.3  takemura 	win_printf(TEXT("DISK_INFO: CHS=%d:%d:%d  block size=%d  flag="),
    175   1.3  takemura 		   ctx->di.di_cylinders,
    176   1.3  takemura 		   ctx->di.di_heads,
    177   1.3  takemura 		   ctx->di.di_sectors,
    178   1.3  takemura 		   ctx->di.di_bytes_per_sect);
    179   1.3  takemura 	if (ctx->di.di_flags & DISK_INFO_FLAG_MBR) {
    180   1.3  takemura 		win_printf(TEXT("MBR "));
    181   1.3  takemura 	}
    182   1.3  takemura 	if (ctx->di.di_flags & DISK_INFO_FLAG_CHS_UNCERTAIN) {
    183   1.3  takemura 		win_printf(TEXT("CHS_UNCERTAIN "));
    184   1.3  takemura 	}
    185   1.3  takemura 	if (ctx->di.di_flags & DISK_INFO_FLAG_UNFORMATTED) {
    186   1.3  takemura 		win_printf(TEXT("UNFORMATTED "));
    187   1.3  takemura 	}
    188   1.3  takemura 	if (ctx->di.di_flags & DISK_INFO_FLAG_PAGEABLE) {
    189   1.3  takemura 		win_printf(TEXT("PAGEABLE "));
    190   1.3  takemura 	}
    191   1.3  takemura 	win_printf(TEXT("\n"));
    192   1.3  takemura #endif /* DEBUG */
    193   1.3  takemura 
    194   1.3  takemura 	if (!(ctx->di.di_flags & DISK_INFO_FLAG_MBR) ||
    195   1.3  takemura 	     (ctx->di.di_flags & DISK_INFO_FLAG_CHS_UNCERTAIN) ||
    196   1.3  takemura 	     (ctx->di.di_flags & DISK_INFO_FLAG_UNFORMATTED) ||
    197   1.3  takemura 	     (ctx->di.di_bytes_per_sect != BLKSZ)) {
    198   1.3  takemura 		win_printf(TEXT("invalid flags\n"));
    199   1.3  takemura 		error = EINVAL;
    200   1.3  takemura 		goto end;
    201   1.3  takemura 	}
    202   1.3  takemura 
    203   1.3  takemura 	/*
    204   1.3  takemura 	 *  read MBR
    205   1.3  takemura 	 */
    206   1.3  takemura 	if (error = rawread(ctx, MBR_BBSECTOR, 1, ctx->buf)) {
    207   1.3  takemura 		goto end;
    208   1.3  takemura 	}
    209   1.5     lukem 	memcpy(&ctx->mbr, &ctx->buf[MBR_PART_OFFSET], sizeof(ctx->mbr));
    210   1.3  takemura 
    211   1.5     lukem 	for (i = 0; i < MBR_PART_COUNT; i++) {
    212   1.3  takemura 	        DEBUG_PRINTF((TEXT("%d: type=%d %d(%d) (%d:%d:%d - %d:%d:%d)")
    213   1.3  takemura 			      TEXT(" flag=0x%02x\n"),
    214   1.3  takemura 			      i,
    215   1.5     lukem 			      ctx->mbr[i].mbrp_type,
    216   1.3  takemura 			      ctx->mbr[i].mbrp_start,
    217   1.3  takemura 			      ctx->mbr[i].mbrp_size,
    218   1.3  takemura 			      ctx->mbr[i].mbrp_scyl,
    219   1.3  takemura 			      ctx->mbr[i].mbrp_shd,
    220   1.3  takemura 			      ctx->mbr[i].mbrp_ssect,
    221   1.3  takemura 			      ctx->mbr[i].mbrp_ecyl,
    222   1.3  takemura 			      ctx->mbr[i].mbrp_ehd,
    223   1.3  takemura 			      ctx->mbr[i].mbrp_esect,
    224   1.3  takemura 			      ctx->mbr[i].mbrp_flag));
    225   1.3  takemura 	}
    226   1.3  takemura 
    227   1.3  takemura 	/*
    228   1.3  takemura 	 *  find BSD partition
    229   1.3  takemura 	 */
    230   1.3  takemura 	ctx->start = -1;
    231   1.3  takemura 	start_386bsd = -1;
    232   1.5     lukem 	for (i = 0; i < MBR_PART_COUNT; i++) {
    233   1.5     lukem 		if (ctx->mbr[i].mbrp_type == MBR_PTYPE_NETBSD) {
    234   1.3  takemura 			ctx->start = ctx->mbr[i].mbrp_start;
    235   1.3  takemura 			break;
    236   1.3  takemura 		}
    237   1.5     lukem 		if (ctx->mbr[i].mbrp_type == MBR_PTYPE_386BSD) {
    238   1.3  takemura 			start_386bsd = ctx->mbr[i].mbrp_start;
    239   1.3  takemura 		}
    240   1.3  takemura 	}
    241   1.3  takemura 	if (ctx->start == -1) {
    242   1.3  takemura 		ctx->start = start_386bsd;
    243   1.3  takemura 	}
    244   1.3  takemura 
    245   1.3  takemura 	if (ctx->start == -1) {
    246   1.3  takemura 		/*
    247   1.3  takemura 		 *  BSD partition is not found.
    248   1.3  takemura 		 *  Try to use entire disk.
    249   1.3  takemura 		 */
    250   1.3  takemura 		ctx->start = 0;
    251   1.3  takemura 		win_printf(TEXT("no BSD partition, start sector=0x%x\n"),
    252   1.3  takemura 			   ctx->start);
    253   1.3  takemura 		goto end;
    254   1.3  takemura 	}
    255   1.3  takemura 
    256   1.3  takemura 	/*
    257   1.3  takemura 	 *  read disklabel
    258   1.3  takemura 	 */
    259   1.3  takemura 	if (error = rawread(ctx, ctx->start + LABELSECTOR, 1, ctx->buf)) {
    260   1.3  takemura 		goto end;
    261   1.3  takemura 	}
    262   1.3  takemura 	memcpy(&ctx->dl, &ctx->buf[LABELOFFSET], sizeof(ctx->dl));
    263   1.3  takemura 
    264   1.3  takemura 	if (ctx->dl.d_magic != DISKMAGIC ||
    265   1.3  takemura 	    ctx->dl.d_magic2 != DISKMAGIC ||
    266   1.3  takemura 	    dkcksum(&ctx->dl) != 0) {
    267   1.3  takemura 		win_printf(TEXT("invalid disklabel, start sector=0x%x\n"),
    268   1.3  takemura 			   ctx->start);
    269   1.3  takemura 		/*
    270   1.3  takemura 		 *  Disklabel is not found.
    271   1.3  takemura 		 *  Try to use entire partition.
    272   1.3  takemura 		 */
    273   1.3  takemura 		goto end;
    274   1.3  takemura 	}
    275   1.3  takemura 
    276   1.3  takemura 	if (partition < 0 || ctx->dl.d_npartitions <= partition) {
    277   1.3  takemura 		error = EINVAL;
    278   1.3  takemura 		goto end;
    279   1.3  takemura 	}
    280   1.3  takemura 
    281   1.3  takemura 	ctx->start = ctx->dl.d_partitions[partition].p_offset;
    282   1.3  takemura 	win_printf(TEXT("start sector=0x%x\n"), ctx->start);
    283   1.3  takemura 
    284   1.3  takemura       end:
    285   1.3  takemura 	if (error && ctx) {
    286   1.7  christos 		dealloc(ctx, sizeof(*ctx));
    287   1.3  takemura 		f->f_devdata = NULL;
    288   1.3  takemura 	}
    289   1.3  takemura 	return (error);
    290   1.3  takemura }
    291   1.3  takemura 
    292   1.3  takemura int
    293   1.8       dsl winblkclose(struct open_file *f)
    294   1.3  takemura {
    295   1.3  takemura 	struct winblk *ctx = f->f_devdata;
    296   1.3  takemura 
    297   1.7  christos 	dealloc(ctx, sizeof(*ctx));
    298   1.3  takemura 
    299   1.3  takemura 	f->f_devdata = NULL;
    300   1.3  takemura 	return (0);
    301   1.3  takemura }
    302   1.3  takemura 
    303   1.3  takemura int
    304   1.8       dsl winblkioctl(struct open_file *f, u_long cmd, void *arg)
    305   1.3  takemura {
    306   1.3  takemura 	return EIO;
    307   1.3  takemura }
    308   1.3  takemura 
    309   1.3  takemura static int
    310   1.9       dsl rawread(struct winblk *ctx, int start, int nsecs, char *buf)
    311   1.3  takemura {
    312   1.3  takemura 	SG_REQ req;
    313   1.3  takemura 	DWORD res;
    314   1.3  takemura 
    315   1.3  takemura 	req.sr_start = start;
    316   1.3  takemura 	req.sr_num_sec = nsecs;
    317   1.3  takemura 	req.sr_num_sg = 1;
    318   1.3  takemura 	req.sr_callback = NULL;
    319   1.3  takemura 	req.sr_sglist[0].sb_buf = buf;
    320   1.3  takemura 	req.sr_sglist[0].sb_len = nsecs * BLKSZ;
    321   1.3  takemura 
    322   1.3  takemura 	DEBUG_PRINTF((TEXT("rawread(0x%x, %d)"), start, nsecs));
    323   1.3  takemura 	if (!DeviceIoControl(ctx->hDevice, DISK_IOCTL_READ,
    324   1.3  takemura 			     &req, sizeof(req),
    325   1.3  takemura 			     NULL, 0, &res, NULL)) {
    326   1.3  takemura 		win_printf(TEXT("DeviceIoControl() failed.error=%d\n"),
    327   1.3  takemura 			   GetLastError());
    328   1.3  takemura 
    329   1.3  takemura 		return (EIO); /* XXX, We shuld check GetLastError(). */
    330   1.3  takemura 	}
    331   1.3  takemura 	DEBUG_PRINTF((TEXT("=%d\n"), req.sr_status));
    332   1.3  takemura 
    333   1.3  takemura 	if (req.sr_status != ERROR_SUCCESS) {
    334   1.3  takemura 		win_printf(TEXT("DeviceIoControl(READ): status=%d\n"),
    335   1.3  takemura 			   req.sr_status);
    336   1.3  takemura 		return (EIO); /* XXX, We shuld check error code. */
    337   1.3  takemura 	}
    338   1.3  takemura 
    339   1.3  takemura 	return (0);
    340   1.3  takemura }
    341