Index: stand/i386/libi386/Makefile =================================================================== --- stand/i386/libi386/Makefile +++ stand/i386/libi386/Makefile @@ -4,7 +4,7 @@ LIB= i386 -SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \ +SRCS= bio.c biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \ biospci.c biossmap.c bootinfo.c bootinfo32.c bootinfo64.c \ comconsole.c devicename.c elf32_freebsd.c \ elf64_freebsd.c multiboot.c multiboot_tramp.S relocater_tramp.S \ Index: stand/i386/libi386/bio.c =================================================================== --- /dev/null +++ stand/i386/libi386/bio.c @@ -0,0 +1,61 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include "libi386.h" + +/* + * The idea is borrowed from pxe.c and zfsimpl.c. The original buffer + * space in pxe.c was 2x 0x2000. Allocating it from BSS will give us needed + * memory below 1MB and usable for real mode calls. + */ + +static char bio_buffer[BIO_BUFFER_SIZE]; +static char *bio_buffer_end = bio_buffer + BIO_BUFFER_SIZE; +static char *bio_buffer_ptr = bio_buffer; + +void * +bio_alloc(size_t size) +{ + char *ptr; + + ptr = bio_buffer_ptr; + if (ptr + size > bio_buffer_end) + return (NULL); + bio_buffer_ptr += size; + + return (ptr); +} + +void +bio_free(void *ptr, size_t size) +{ + + if (ptr == NULL) + return; + + bio_buffer_ptr -= size; + if (bio_buffer_ptr != ptr) + panic("bio_alloc()/bio_free() mismatch\n"); +} Index: stand/i386/libi386/biosdisk.c =================================================================== --- stand/i386/libi386/biosdisk.c +++ stand/i386/libi386/biosdisk.c @@ -448,16 +448,29 @@ char *buf, size_t *rsize) { struct disk_devdesc *dev = (struct disk_devdesc *)devdata; - uint64_t disk_blocks; - int blks, rc; + uint64_t disk_blocks, offset; + size_t blks, blkoff, bsize, bio_size, rest; + caddr_t bbuf; + int rc; - if (size % BD(dev).bd_sectorsize) { - panic("bd_strategy: %d bytes I/O not multiple of block size", - size); + /* + * First make sure the IO size is a multiple of 512 bytes. While we do + * process partial reads below, the strategy mechanism is built + * assuming IO is a multiple of 512B blocks. If the request is not + * a multiple of 512B blocks, it has to be some sort of bug. + */ + if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) { + printf("bd_strategy: %d bytes I/O not multiple of %d\n", + size, BIOSDISK_SECSIZE); + return (EIO); } DEBUG("open_disk %p", dev); + offset = dblk * BIOSDISK_SECSIZE; + dblk = offset / BD(dev).bd_sectorsize; + blkoff = offset % BD(dev).bd_sectorsize; + /* * Check the value of the size argument. We do have quite small * heap (64MB), but we do not know good upper limit, so we check against @@ -465,11 +478,14 @@ * while translating block count to bytes. */ if (size > INT_MAX) { - DEBUG("too large read: %zu bytes", size); + DEBUG("too large I/O: %zu bytes", size); return (EIO); } blks = size / BD(dev).bd_sectorsize; + if (blks == 0 || (size % BD(dev).bd_sectorsize) != 0) + blks++; + if (dblk > dblk + blks) return (EIO); @@ -498,38 +514,96 @@ if (dblk + blks >= dev->d_offset + disk_blocks) { blks = dev->d_offset + disk_blocks - dblk; size = blks * BD(dev).bd_sectorsize; - DEBUG("short read %d", blks); + DEBUG("short I/O %d", blks); } - switch (rw & F_MASK) { - case F_READ: - DEBUG("read %d from %lld to %p", blks, dblk, buf); + bio_size = min(BIO_BUFFER_SIZE, size); + while (bio_size > BD(dev).bd_sectorsize) { + bbuf = bio_alloc(bio_size); + if (bbuf != NULL) + break; + bio_size -= BD(dev).bd_sectorsize; + } + if (bbuf == NULL) { + bio_size = V86_IO_BUFFER_SIZE; + if (bio_size / BD(dev).bd_sectorsize == 0) + panic("BUG: Real mode buffer is too small\n"); - if (blks && (rc = bd_io(dev, dblk, blks, buf, BD_RD))) { - /* Filter out floppy controller errors */ - if (BD(dev).bd_flags != BD_FLOPPY || rc != 0x20) { - printf("read %d from %lld to %p, error: 0x%x\n", - blks, dblk, buf, rc); + /* Use alternate 4k buffer */ + bbuf = PTOV(V86_IO_BUFFER); + } + rest = size; + rc = 0; + while (blks > 0) { + int x = min(blks, bio_size / BD(dev).bd_sectorsize); + + switch (rw & F_MASK) { + case F_READ: + DEBUG("read %d from %lld to %p", x, dblk, buf); + bsize = BD(dev).bd_sectorsize * x - blkoff; + if (rest < bsize) + bsize = rest; + + if ((rc = bd_io(dev, dblk, x, bbuf, BD_RD)) != 0) { + rc = EIO; + goto error; } - return (EIO); - } - break; - case F_WRITE : - DEBUG("write %d from %lld to %p", blks, dblk, buf); - if (blks && bd_io(dev, dblk, blks, buf, BD_WR)) { - DEBUG("write error"); - return (EIO); + bcopy(bbuf + blkoff, buf, bsize); + break; + case F_WRITE : + DEBUG("write %d from %lld to %p", x, dblk, buf); + if (blkoff != 0) { + /* + * We got offset to sector, read 1 sector to + * bbuf. + */ + x = 1; + bsize = BD(dev).bd_sectorsize - blkoff; + bsize = min(bsize, rest); + rc = bd_io(dev, dblk, x, bbuf, BD_RD); + } else if (rest < BD(dev).bd_sectorsize) { + /* + * The remaining block is not full + * sector. Read 1 sector to bbuf. + */ + x = 1; + bsize = rest; + rc = bd_io(dev, dblk, x, bbuf, BD_RD); + } else { + /* We can write full sector(s). */ + bsize = BD(dev).bd_sectorsize * x; + } + /* + * Put your Data In, Put your Data out, + * Put your Data In, and shake it all about + */ + bcopy(buf, bbuf + blkoff, bsize); + if ((rc = bd_io(dev, dblk, x, bbuf, BD_WR)) != 0) { + rc = EIO; + goto error; + } + + break; + default: + /* DO NOTHING */ + rc = EROFS; + goto error; } - break; - default: - /* DO NOTHING */ - return (EROFS); + + blkoff = 0; + buf += bsize; + rest -= bsize; + blks -= x; + dblk += x; } - if (rsize) + if (rsize != NULL) *rsize = size; - return (0); +error: + if (bbuf != PTOV(V86_IO_BUFFER)) + bio_free(bbuf, bio_size); + return (rc); } static int @@ -604,21 +678,16 @@ bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, BD_RD); } - static int bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int dowrite) { - u_int x, sec, result, resid, retry, maxfer; - caddr_t p, xp, bbuf; - + int result, retry; + /* Just in case some idiot actually tries to read/write -1 blocks... */ if (blks < 0) return (-1); - resid = blks; - p = dest; - /* * Workaround for a problem with some HP ProLiant BIOS failing to work * out the boot disk after installation. hrs and kuriyama discovered @@ -627,91 +696,49 @@ * the bios. The problem is alleviated by doing an extra read before * the buggy read. It is not immediately known whether other models * are similarly affected. + * Loop retrying the operation a couple of times. The BIOS + * may also retry. */ if (dowrite == BD_RD && dblk >= 0x100000000) bd_io_workaround(dev); + for (retry = 0; retry < 3; retry++) { + /* if retrying, reset the drive */ + if (retry > 0) { + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0; + v86.edx = BD(dev).bd_unit; + v86int(); + } - /* Decide whether we have to bounce */ - if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 && - (VTOP(dest) >> 16) != - (VTOP(dest + blks * BD(dev).bd_sectorsize) >> 16))) { + if (BD(dev).bd_flags & BD_MODEEDD1) + result = bd_edd_io(dev, dblk, blks, dest, dowrite); + else + result = bd_chs_io(dev, dblk, blks, dest, dowrite); - /* - * There is a 64k physical boundary somewhere in the - * destination buffer, or the destination buffer is above - * first 1MB of physical memory so we have to arrange a - * suitable bounce buffer. Allocate a buffer twice as large - * as we need to. Use the bottom half unless there is a break - * there, in which case we use the top half. - */ - x = V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize; - x = min(x, (unsigned)blks); - bbuf = PTOV(V86_IO_BUFFER); - maxfer = x; /* limit transfers to bounce region size */ - } else { - bbuf = NULL; - maxfer = 0; + if (result == 0) + break; } - - while (resid > 0) { - /* - * Play it safe and don't cross track boundaries. - * (XXX this is probably unnecessary) - */ - sec = dblk % BD(dev).bd_sec; /* offset into track */ - x = min(BD(dev).bd_sec - sec, resid); - if (maxfer > 0) - x = min(x, maxfer); /* fit bounce buffer */ - /* where do we transfer to? */ - xp = bbuf == NULL ? p : bbuf; - - /* - * Put your Data In, Put your Data out, - * Put your Data In, and shake it all about - */ - if (dowrite == BD_WR && bbuf != NULL) - bcopy(p, bbuf, x * BD(dev).bd_sectorsize); - - /* - * Loop retrying the operation a couple of times. The BIOS - * may also retry. - */ - for (retry = 0; retry < 3; retry++) { - /* if retrying, reset the drive */ - if (retry > 0) { - v86.ctl = V86_FLAGS; - v86.addr = 0x13; - v86.eax = 0; - v86.edx = BD(dev).bd_unit; - v86int(); - } - - if (BD(dev).bd_flags & BD_MODEEDD1) - result = bd_edd_io(dev, dblk, x, xp, dowrite); - else - result = bd_chs_io(dev, dblk, x, xp, dowrite); - if (result == 0) - break; + /* + * 0x20 - Controller failure. This is common error when the + * media is not present. + */ + if (result != 0 && result != 0x20) { + if (dowrite == BD_WR) { + printf("%s%d: Write %d sector(s) from %p (0x%x) " + "to %lld: 0x%x\n", dev->dd.d_dev->dv_name, + dev->dd.d_unit, blks, dest, VTOP(dest), dblk, + result); + } else { + printf("%s%d: Read %d sector(s) from %lld to %p " + "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name, + dev->dd.d_unit, blks, dblk, dest, VTOP(dest), + result); } - - if (dowrite == BD_WR) - DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x, - p, VTOP(p), dblk, result ? "failed" : "ok"); - else - DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x, - dblk, p, VTOP(p), result ? "failed" : "ok"); - if (result) { - return (result); - } - if (dowrite == BD_RD && bbuf != NULL) - bcopy(bbuf, p, x * BD(dev).bd_sectorsize); - p += (x * BD(dev).bd_sectorsize); - dblk += x; - resid -= x; } - return (0); + return (result); } /* Index: stand/i386/libi386/libi386.h =================================================================== --- stand/i386/libi386/libi386.h +++ stand/i386/libi386/libi386.h @@ -123,6 +123,11 @@ extern uint32_t high_heap_size; /* extended memory region available */ extern vm_offset_t high_heap_base; /* for use as the heap */ +/* 16KB buffer space for real mode data transfers. */ +#define BIO_BUFFER_SIZE 0x4000 +void *bio_alloc(size_t size); +void bio_free(void *ptr, size_t size); + /* * Values for width parameter to biospci_{read,write}_config */ Index: stand/i386/libi386/pxe.c =================================================================== --- stand/i386/libi386/pxe.c +++ stand/i386/libi386/pxe.c @@ -48,18 +48,10 @@ #include #include +#include "libi386.h" #include "btxv86.h" #include "pxe.h" -/* - * Allocate the PXE buffers statically instead of sticking grimy fingers into - * BTX's private data area. The scratch buffer is used to send information to - * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS. - */ -#define PXE_BUFFER_SIZE 0x2000 -static char scratch_buffer[PXE_BUFFER_SIZE]; -static char data_buffer[PXE_BUFFER_SIZE]; - static pxenv_t *pxenv_p = NULL; /* PXENV+ */ static pxe_t *pxe_p = NULL; /* !PXE */ @@ -68,9 +60,9 @@ #endif void pxe_enable(void *pxeinfo); -static void (*pxe_call)(int func); -static void pxenv_call(int func); -static void bangpxe_call(int func); +static void (*pxe_call)(int func, void *ptr); +static void pxenv_call(int func, void *ptr); +static void bangpxe_call(int func, void *ptr); static int pxe_init(void); static int pxe_print(int verbose); @@ -225,12 +217,17 @@ printf("@%04x:%04x\n", pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); - gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer; + gci_p = bio_alloc(sizeof(*gci_p)); + if (gci_p == NULL) { + pxe_p = NULL; + return (0); + } bzero(gci_p, sizeof(*gci_p)); gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; - pxe_call(PXENV_GET_CACHED_INFO); + pxe_call(PXENV_GET_CACHED_INFO, gci_p); if (gci_p->Status != 0) { pxe_perror(gci_p->Status); + bio_free(gci_p, sizeof(*gci_p)); pxe_p = NULL; return (0); } @@ -240,6 +237,7 @@ bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), bootp_response, bootp_response_size); } + bio_free(gci_p, sizeof(*gci_p)); return (1); } @@ -262,31 +260,37 @@ static void pxe_cleanup(void) { -#ifdef PXE_DEBUG - t_PXENV_UNLOAD_STACK *unload_stack_p = - (t_PXENV_UNLOAD_STACK *)scratch_buffer; - t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p = - (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; -#endif + t_PXENV_UNLOAD_STACK *unload_stack_p; + t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p; if (pxe_call == NULL) return; - pxe_call(PXENV_UNDI_SHUTDOWN); + undi_shutdown_p = bio_alloc(sizeof(*undi_shutdown_p)); + if (undi_shutdown_p != NULL) { + bzero(undi_shutdown_p, sizeof(*undi_shutdown_p)); + pxe_call(PXENV_UNDI_SHUTDOWN, undi_shutdown_p); #ifdef PXE_DEBUG - if (pxe_debug && undi_shutdown_p->Status != 0) - printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", - undi_shutdown_p->Status); + if (pxe_debug && undi_shutdown_p->Status != 0) + printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", + undi_shutdown_p->Status); #endif + bio_free(undi_shutdown_p, sizeof(*undi_shutdown_p)); + } - pxe_call(PXENV_UNLOAD_STACK); + unload_stack_p = bio_alloc(sizeof(*unload_stack_p)); + if (unload_stack_p != NULL) { + bzero(unload_stack_p, sizeof(*unload_stack_p)); + pxe_call(PXENV_UNLOAD_STACK, unload_stack_p); #ifdef PXE_DEBUG - if (pxe_debug && unload_stack_p->Status != 0) - printf("pxe_cleanup: UNLOAD_STACK failed %x\n", - unload_stack_p->Status); + if (pxe_debug && unload_stack_p->Status != 0) + printf("pxe_cleanup: UNLOAD_STACK failed %x\n", + unload_stack_p->Status); #endif + bio_free(unload_stack_p, sizeof(*unload_stack_p)); + } } void @@ -296,7 +300,7 @@ } void -pxenv_call(int func) +pxenv_call(int func, void *ptr) { #ifdef PXE_DEBUG if (pxe_debug) @@ -304,14 +308,13 @@ #endif bzero(&v86, sizeof(v86)); - bzero(data_buffer, sizeof(data_buffer)); __pxenvseg = pxenv_p->RMEntry.segment; __pxenvoff = pxenv_p->RMEntry.offset; v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; - v86.es = VTOPSEG(scratch_buffer); - v86.edi = VTOPOFF(scratch_buffer); + v86.es = VTOPSEG(ptr); + v86.edi = VTOPOFF(ptr); v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry); v86.ebx = func; v86int(); @@ -319,7 +322,7 @@ } void -bangpxe_call(int func) +bangpxe_call(int func, void *ptr) { #ifdef PXE_DEBUG if (pxe_debug) @@ -327,14 +330,13 @@ #endif bzero(&v86, sizeof(v86)); - bzero(data_buffer, sizeof(data_buffer)); __bangpxeseg = pxe_p->EntryPointSP.segment; __bangpxeoff = pxe_p->EntryPointSP.offset; v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; - v86.edx = VTOPSEG(scratch_buffer); - v86.eax = VTOPOFF(scratch_buffer); + v86.edx = VTOPSEG(ptr); + v86.eax = VTOPOFF(ptr); v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry); v86.ebx = func; v86int(); @@ -362,11 +364,14 @@ { t_PXENV_UNDI_CLOSE *undi_close_p; - undi_close_p = (t_PXENV_UNDI_CLOSE *)scratch_buffer; - bzero(undi_close_p, sizeof(*undi_close_p)); - pxe_call(PXENV_UNDI_CLOSE); - if (undi_close_p->Status != 0) - printf("undi close failed: %x\n", undi_close_p->Status); + undi_close_p = bio_alloc(sizeof(*undi_close_p)); + if (undi_close_p != NULL) { + bzero(undi_close_p, sizeof(*undi_close_p)); + pxe_call(PXENV_UNDI_CLOSE, undi_close_p); + if (undi_close_p->Status != 0) + printf("undi close failed: %x\n", undi_close_p->Status); + bio_free(undi_close_p, sizeof(*undi_close_p)); + } } static void @@ -377,11 +382,15 @@ uint8_t *mac; int i, len; - undi_info_p = (t_PXENV_UNDI_GET_INFORMATION *)scratch_buffer; + undi_info_p = bio_alloc(sizeof(*undi_info_p)); + if (undi_info_p == NULL) + return; + bzero(undi_info_p, sizeof(*undi_info_p)); - pxe_call(PXENV_UNDI_GET_INFORMATION); + pxe_call(PXENV_UNDI_GET_INFORMATION, undi_info_p); if (undi_info_p->Status != 0) { printf("undi get info failed: %x\n", undi_info_p->Status); + bio_free(undi_info_p, sizeof(*undi_info_p)); return; } @@ -410,32 +419,44 @@ else desc->xid = 0; - undi_open_p = (t_PXENV_UNDI_OPEN *)scratch_buffer; + bio_free(undi_info_p, sizeof(*undi_info_p)); + undi_open_p = bio_alloc(sizeof(*undi_open_p)); + if (undi_open_p == NULL) + return; bzero(undi_open_p, sizeof(*undi_open_p)); undi_open_p->PktFilter = FLTR_DIRECTED | FLTR_BRDCST; - pxe_call(PXENV_UNDI_OPEN); + pxe_call(PXENV_UNDI_OPEN, undi_open_p); if (undi_open_p->Status != 0) printf("undi open failed: %x\n", undi_open_p->Status); + bio_free(undi_open_p, sizeof(*undi_open_p)); } static int pxe_netif_receive(void **pkt) { - t_PXENV_UNDI_ISR *isr = (t_PXENV_UNDI_ISR *)scratch_buffer; + t_PXENV_UNDI_ISR *isr; char *buf, *ptr, *frame; size_t size, rsize; + isr = bio_alloc(sizeof(*isr)); + if (isr == NULL) + return (-1); + bzero(isr, sizeof(*isr)); isr->FuncFlag = PXENV_UNDI_ISR_IN_START; - pxe_call(PXENV_UNDI_ISR); - if (isr->Status != 0) + pxe_call(PXENV_UNDI_ISR, isr); + if (isr->Status != 0) { + bio_free(isr, sizeof(*isr)); return (-1); + } bzero(isr, sizeof(*isr)); isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; - pxe_call(PXENV_UNDI_ISR); - if (isr->Status != 0) + pxe_call(PXENV_UNDI_ISR, isr); + if (isr->Status != 0) { + bio_free(isr, sizeof(*isr)); return (-1); + } while (isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) { /* @@ -443,26 +464,31 @@ */ bzero(isr, sizeof(*isr)); isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; - pxe_call(PXENV_UNDI_ISR); + pxe_call(PXENV_UNDI_ISR, isr); if (isr->Status != 0 || - isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) + isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) { + bio_free(isr, sizeof(*isr)); return (-1); + } } while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) { if (isr->Status != 0 || isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) { + bio_free(isr, sizeof(*isr)); return (-1); } bzero(isr, sizeof(*isr)); isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; - pxe_call(PXENV_UNDI_ISR); + pxe_call(PXENV_UNDI_ISR, isr); } size = isr->FrameLength; buf = malloc(size + ETHER_ALIGN); - if (buf == NULL) + if (buf == NULL) { + bio_free(isr, sizeof(*isr)); return (-1); + } ptr = buf + ETHER_ALIGN; rsize = 0; @@ -475,8 +501,9 @@ bzero(isr, sizeof(*isr)); isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; - pxe_call(PXENV_UNDI_ISR); + pxe_call(PXENV_UNDI_ISR, isr); if (isr->Status != 0) { + bio_free(isr, sizeof(*isr)); free(buf); return (-1); } @@ -488,6 +515,7 @@ } *pkt = buf; + bio_free(isr, sizeof(*isr)); return (rsize); } @@ -515,26 +543,31 @@ t_PXENV_UNDI_TRANSMIT *trans_p; t_PXENV_UNDI_TBD *tbd_p; char *data; + ssize_t rv = -1; - trans_p = (t_PXENV_UNDI_TRANSMIT *)scratch_buffer; - bzero(trans_p, sizeof(*trans_p)); - tbd_p = (t_PXENV_UNDI_TBD *)(scratch_buffer + sizeof(*trans_p)); - bzero(tbd_p, sizeof(*tbd_p)); + trans_p = bio_alloc(sizeof(*trans_p)); + tbd_p = bio_alloc(sizeof(*tbd_p)); + data = bio_alloc(len); - data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p); + if (trans_p != NULL && tbd_p != NULL && data != NULL) { + bzero(trans_p, sizeof(*trans_p)); + bzero(tbd_p, sizeof(*tbd_p)); - trans_p->TBD.segment = VTOPSEG(tbd_p); - trans_p->TBD.offset = VTOPOFF(tbd_p); + trans_p->TBD.segment = VTOPSEG(tbd_p); + trans_p->TBD.offset = VTOPOFF(tbd_p); - tbd_p->ImmedLength = len; - tbd_p->Xmit.segment = VTOPSEG(data); - tbd_p->Xmit.offset = VTOPOFF(data); - bcopy(pkt, data, len); + tbd_p->ImmedLength = len; + tbd_p->Xmit.segment = VTOPSEG(data); + tbd_p->Xmit.offset = VTOPOFF(data); + bcopy(pkt, data, len); - pxe_call(PXENV_UNDI_TRANSMIT); - if (trans_p->Status != 0) { - return (-1); + pxe_call(PXENV_UNDI_TRANSMIT, trans_p); + if (trans_p->Status == 0) + rv = len; } - return (len); + bio_free(data, len); + bio_free(tbd_p, sizeof(*tbd_p)); + bio_free(trans_p, sizeof(*trans_p)); + return (rv); }