From 741ed6fa8609b0a8ce1fa9b1abc27916326b95f9 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 21 Feb 2010 17:53:23 -0800 Subject: [PATCH] core: rewrite loadhigh in C Rewrite the loadhight function in C, and eliminate double usage of xfer_buf_seg. Signed-off-by: H. Peter Anvin --- core/fs/loadhigh.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++ core/loadhigh.inc | 70 ++++----------------------------- 2 files changed, 121 insertions(+), 62 deletions(-) create mode 100644 core/fs/loadhigh.c diff --git a/core/fs/loadhigh.c b/core/fs/loadhigh.c new file mode 100644 index 0000000..e365b1a --- /dev/null +++ b/core/fs/loadhigh.c @@ -0,0 +1,113 @@ +/* + * ----------------------------------------------------------------------- + * + * Copyright 1994-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * loadhigh.c + * + * An alternate interface to getfssec. + * + * Inputs: SI = file handle/cluster pointer + * EDI = target address in high memory + * EAX = maximum number of bytes to load + * DX = zero-padding mask (e.g. 0003h for pad to dword) + * BX = 16-bit subroutine to call at the top of each loop + * (to print status and check for abort) + * EBP = maximum load address + * + * Outputs: SI = file handle/cluster pointer + * EBX = first untouched address (not including padding) + * EDI = first untouched address (including padding) + * CF = reached EOF + * OF = ran out of high memory + */ + +#include +#include +#include "core.h" +#include "fs.h" + +#define MAX_CHUNK (1 << 20) /* 1 MB */ + +void pm_load_high(com32sys_t *regs) +{ + struct fs_info *fs; + uint32_t bytes; + uint32_t zero_mask; + bool have_more; + uint32_t bytes_read; + char *buf, *limit; + struct file *file; + uint32_t sector_mask; + size_t pad; + + bytes = regs->eax.l; + zero_mask = regs->edx.w[0]; + buf = (char *)regs->edi.l; + limit = (char *)(regs->ebp.l & ~zero_mask); + file = handle_to_file(regs->esi.w[0]); + fs = file->fs; + + regs->eflags.l &= ~(EFLAGS_CF|EFLAGS_OF|EFLAGS_AF| + EFLAGS_PF|EFLAGS_ZF|EFLAGS_SF); + + sector_mask = SECTOR_SIZE(fs) - 1; + + while (bytes) { + uint32_t sectors; + uint32_t chunk; + + if (buf + SECTOR_SIZE(fs) > limit) { + /* Can't fit even one more sector in... */ + regs->eflags.l |= EFLAGS_OF; + break; + } + + chunk = bytes; + + if (regs->ebx.w[0]) { + call16((void (*)(void))(size_t)regs->ebx.w[0], &zero_regs, NULL); + chunk = min(chunk, MAX_CHUNK); + } + + if (chunk > (((char *)limit - buf) & ~sector_mask)) + chunk = ((char *)limit - buf) & ~sector_mask; + + sectors = (chunk + sector_mask) >> SECTOR_SHIFT(fs); + bytes_read = fs->fs_ops->getfssec(file, buf, sectors, &have_more); + + if (bytes_read > chunk) + bytes_read = chunk; + + buf += bytes_read; + bytes -= bytes_read; + + if (!have_more) { + /* + * If we reach EOF, the filesystem driver will have already closed + * the underlying file... this really should be cleaner. + */ + _close_file(file); + regs->esi.w[0] = 0; + regs->eflags.l |= EFLAGS_CF; + break; + } + } + + pad = (size_t)buf & zero_mask; + if (pad) + memset(buf, 0, pad); + + regs->ebx.l = (size_t)buf; + regs->edi.l = (size_t)buf + pad; +} diff --git a/core/loadhigh.inc b/core/loadhigh.inc index 205c3e6..89de5e8 100644 --- a/core/loadhigh.inc +++ b/core/loadhigh.inc @@ -1,7 +1,7 @@ ;; ----------------------------------------------------------------------- ;; ;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved -;; Copyright 2009 Intel Corporation; author: H. Peter Anvin +;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -21,83 +21,29 @@ ; ; load_high: loads (the remainder of) a file into high memory. -; This routine prints dots for each 64K transferred, and -; calls abort_check periodically. -; -; The xfer_buf_seg is used as a bounce buffer. ; ; Assumes CS == DS. ; -; The input address (EDI) should be dword aligned, and the final -; stretch is padded with zeroes if necessary. -; ; Inputs: SI = file handle/cluster pointer ; EDI = target address in high memory ; EAX = maximum number of bytes to load ; DX = zero-padding mask (e.g. 0003h for pad to dword) ; BX = subroutine to call at the top of each loop ; (to print status and check for abort) -; MyHighMemSize = maximum load address +; [MyHighMemSize] = maximum load address ; ; Outputs: SI = file handle/cluster pointer ; EBX = first untouched address (not including padding) ; EDI = first untouched address (including padding) ; CF = reached EOF ; + extern pm_load_high load_high: - push es ; ES - - mov cx,xfer_buf_seg - mov es,cx - mov [PauseBird],bx - -.read_loop: - and si,si ; If SI == 0 then we have end of file - jz .eof - call [PauseBird] - - push eax ; Total bytes to transfer - cmp eax,(1 << 16) ; Max 64K in one transfer - jna .size_ok - mov eax,(1 << 16) -.size_ok: - push eax ; Bytes transferred this chunk - add eax,SECTOR_SIZE-1 - shr eax,SECTOR_SHIFT ; Convert to sectors - - ; Now (e)ax contains the number of sectors to get - push edi ; Target buffer - mov cx,ax - xor bx,bx ; ES:0 - pm_call getfssec ; Load the data into xfer_buf_seg - pop edi ; Target buffer - pushf ; EOF status - lea ebx,[edi+ecx] ; End of data -.fix_slop: - test cx,dx - jz .noslop - ; The last dword fractional - pad with zeroes - ; Zero-padding is critical for multi-file initramfs. - mov byte [es:ecx],0 - inc cx - jmp short .fix_slop -.noslop: - lea eax,[edi+ecx] - cmp eax,[MyHighMemSize] - ja .overflow - - push esi ; File handle/cluster pointer - mov esi,core_xfer_buf ; Source address - call bcopy ; Copy to high memory - pop esi ; File handle/cluster pointer - popf ; EOF status - pop ecx ; Byte count this round - pop eax ; Total bytes to transfer - jc .eof - sub eax,ecx - jnz .read_loop ; More to read... (if ZF=1 then CF=0) -.eof: - pop es ; ES + push ebp + mov ebp,[MyHighMemSize] + pm_call pm_load_high + pop ebp + jo .overflow ret .overflow: mov si,err_nohighmem -- 2.7.4