From 2e91ec5f155f04aee878ed70a04fb5b15e40da3b Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 14 Jul 2010 15:55:25 +0800 Subject: [PATCH] elflink: a lot of core/fs merge As: modified: core/Makefile modified: core/adv.inc modified: core/call16.c modified: core/callback.inc modified: core/comboot.inc modified: core/diskstart.inc deleted: core/extlinux.asm modified: core/include/core.h modified: core/isolinux.asm modified: core/ldlinux.asm modified: core/pmapi.c modified: core/timer.inc modified: elf_gen_dep.sh --- core/Makefile | 7 - core/adv.inc | 42 ++-- core/call16.c | 18 +- core/callback.inc | 13 +- core/comboot.inc | 14 +- core/diskstart.inc | 599 +++++++++++++++++++++++++++++++--------------------- core/extlinux.asm | 38 ---- core/include/core.h | 6 +- core/isolinux.asm | 32 +-- core/ldlinux.asm | 4 + core/pmapi.c | 8 + core/timer.inc | 15 +- elf_gen_dep.sh | 2 +- 13 files changed, 458 insertions(+), 340 deletions(-) delete mode 100644 core/extlinux.asm diff --git a/core/Makefile b/core/Makefile index 8c675c2..54848f2 100644 --- a/core/Makefile +++ b/core/Makefile @@ -33,7 +33,6 @@ CODEPAGE = cp865 # The targets to build in this directory... BTARGET = kwdhash.gen \ - extlinux.bin extlinux.bss extlinux.sys \ ldlinux.bss ldlinux.sys ldlinux.bin \ isolinux.bin isolinux-debug.bin pxelinux.0 @@ -110,12 +109,6 @@ ldlinux.bss: ldlinux.bin ldlinux.sys: ldlinux.bin dd if=$< of=$@ bs=512 skip=1 -extlinux.bss: extlinux.bin - dd if=$< of=$@ bs=512 count=1 - -extlinux.sys: extlinux.bin - dd if=$< of=$@ bs=512 skip=1 - codepage.cp: ../codepage/$(CODEPAGE).cp cp -f $< $@ diff --git a/core/adv.inc b/core/adv.inc index 6725261..0b45a6c 100644 --- a/core/adv.inc +++ b/core/adv.inc @@ -71,18 +71,12 @@ adv_init: cmp word [ADVSectors],2 ; Not present? jb adv_verify - ; - ; Update pointers to default ADVs... - ; - mov bx,[DataSectors] - shl bx,2 - mov ecx,[bsHidden] - mov eax,[bx+SectorPtrs-4]; First ADV sector - mov edx,[bx+SectorPtrs] ; Second ADV sector - add eax,ecx - add edx,ecx - mov [ADVSec0],eax - mov [ADVSec1],edx + mov eax,[Hidden] + mov edx,[Hidden+4] + add [ADVSec0],eax + adc [ADVSec0+4],edx + add [ADVSec1],eax + adc [ADVSec1+4],edx mov al,[DriveNumber] mov [ADVDrive],al jmp adv_read @@ -300,23 +294,26 @@ adv_cleanup: ; Returns CF=1 if the ADV cannot be written. ; adv_write: - cmp dword [ADVSec0],0 + push eax + mov eax,[ADVSec0] + or eax,[ADVSec0+4] je .bad - cmp dword [ADVSec1],0 + mov eax,[ADVSec1] + or eax,[ADVSec1+4] je .bad cmp byte [ADVDrive],-1 je .bad - push ax call adv_cleanup mov ah,3 ; Write call adv_read_write - pop ax clc + pop eax ret .bad: ; No location for ADV set stc + pop eax ret ; @@ -358,10 +355,12 @@ adv_read_write: .noedd: mov eax,[ADVSec0] + mov edx,[ADVSec0+4] mov bx,adv0 call .doone mov eax,[ADVSec1] + mov edx,[ADVSec1+4] mov bx,adv1 call .doone @@ -369,7 +368,6 @@ adv_read_write: ret .doone: - xor edx,edx ; Zero-extend LBA push si jmp si @@ -409,6 +407,9 @@ adv_read_write: push eax push bp + and edx,edx ; > 2 TiB not possible + jnz .cb_overflow + mov dl,[ADVDrive] and dl,dl ; Floppies: can't trust INT 13h 08h, we better know @@ -445,6 +446,7 @@ adv_read_write: ; Dividing by sectors to get (track,sector): we may have ; up to 2^18 tracks, so we need to use 32-bit arithmetric. ; + xor edx,edx div esi xor cx,cx xchg cx,dx ; CX <- sector index (0-based) @@ -495,9 +497,9 @@ adv_read_write: jmp .cb_done section .data16 - alignz 4 -ADVSec0 dd 0 ; Not specified -ADVSec1 dd 0 ; Not specified + alignz 8 +ADVSec0 dq 0 ; Not specified +ADVSec1 dq 0 ; Not specified ADVDrive db -1 ; No ADV defined ADVCHSInfo db -1 ; We have CHS info for this drive diff --git a/core/call16.c b/core/call16.c index 86d7046..095f814 100644 --- a/core/call16.c +++ b/core/call16.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * 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 @@ -17,11 +17,25 @@ */ #include +#include #include "core.h" const com32sys_t zero_regs; /* Common all-zero register set */ +static inline uint32_t eflags(void) +{ + uint32_t v; + + asm volatile("pushfl ; popl %0" : "=rm" (v)); + return v; +} + void call16(void (*func)(void), const com32sys_t *ireg, com32sys_t *oreg) { - core_farcall((size_t)func, ireg, oreg); + com32sys_t xreg = *ireg; + + /* Enable interrupts if and only if they are enabled in the caller */ + xreg.eflags.l = (xreg.eflags.l & ~EFLAGS_IF) | (eflags() & EFLAGS_IF); + + core_farcall((size_t)func, &xreg, oreg); } diff --git a/core/callback.inc b/core/callback.inc index a33b582..d98d800 100644 --- a/core/callback.inc +++ b/core/callback.inc @@ -74,7 +74,7 @@ core_syscall: mov eax,.rm_return ; Return seg:offs stosd ; Save in stack frame mov eax,[edi-12] ; Return flags - and eax,0x200cd7 ; Mask (potentially) unsafe flags + and eax,0x200ed7 ; Mask (potentially) unsafe flags mov [edi-12],eax ; Primary flags entry stosw ; Return flags @@ -84,13 +84,15 @@ core_syscall: bits 16 section .text16 .rm: + mov ax,sp + add ax,9*4+4*2 + mov [CallbackSP],ax pop gs pop fs pop es pop ds popad popfd - mov [cs:CallbackSP],sp retf ; Invoke routine .rm_return: @@ -138,6 +140,7 @@ core_syscall: ; ; Cfarcall invocation. We copy the stack frame to the real-mode stack, ; followed by the return CS:IP and the CS:IP of the target function. +; The value of IF is copied from the calling routine. ; global core_cfarcall core_cfarcall: @@ -156,11 +159,14 @@ core_cfarcall: mov [word CallbackSP],di sub edi,ecx ; Allocate space for stack frame and edi,~3 ; Round - sub edi,4*2 ; Return pointer, return value + sub edi,4*3 ; Return pointer, return value, EFLAGS mov [word RealModeSSSP],di shl ebx,4 add edi,ebx ; Create linear address + mov eax,[esp+5*4] ; EFLAGS from entry + and eax,0x202 ; IF only + stosd mov eax,[esp+7*4] ; CS:IP stosd ; Save to stack frame mov eax,.rm_return ; Return seg:off @@ -179,6 +185,7 @@ core_cfarcall: bits 16 section .text16 .rm: + popfd retf .rm_return: mov sp,[cs:CallbackSP] diff --git a/core/comboot.inc b/core/comboot.inc index 0c9956a..59db7ec 100644 --- a/core/comboot.inc +++ b/core/comboot.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 @@ -593,6 +593,8 @@ comapi_derinfo: mov P_DL,al mov P_FS,cs mov P_SI,OrigESDI + mov P_GS,cs + mov P_DI,Hidden %if IS_SYSLINUX || IS_EXTLINUX mov P_ES,cs mov P_BX,PartInfo @@ -751,11 +753,11 @@ comapi_runkernel: ; It's not just possible, but quite likely, that ES:BX ; points into real_mode_seg or xfer_buf_seg, so we ; need to exercise some special care here... use - ; vk_append for temporary storage. + ; VKernelBuf for temporary storage. push ds mov ds,P_ES mov si,P_BX - mov di,vk_append + mov di,VKernelBuf call strcpy pop ds @@ -784,7 +786,7 @@ comapi_runkernel: push es mov dx,real_mode_seg mov es,dx - mov si,vk_append + mov si,VKernelBuf mov di,cmd_line_here call strcpy mov word [es:di-1],' ' ; Simulate APPEND: space plus null @@ -837,10 +839,10 @@ comapi_userfont: ; %if IS_SYSLINUX || IS_ISOLINUX || IS_EXTLINUX comapi_readdisk: - mov esi,P_ESI ; Enforce ESI == EDI == 0, these - or esi,P_EDI ; are reserved for future expansion + cmp P_EDI,0 ; Reserved for future expansion jnz .err mov eax,P_EDX + mov edx,P_ESI mov es,P_ES mov bx,P_BX mov bp,P_CX ; WE CANNOT use P_* after touching bp! diff --git a/core/diskstart.inc b/core/diskstart.inc index 4084ff7..c61a615 100644 --- a/core/diskstart.inc +++ b/core/diskstart.inc @@ -17,24 +17,25 @@ ; Common early-bootstrap code for harddisk-based Syslinux derivatives. ; - ; Expanded superblock - section .earlybss - alignb 8 -SuperInfo resq 16 ; The first 16 bytes expanded 8 times -DriveNumber resb 1 - section .init ; ; Some of the things that have to be saved very early are saved ; "close" to the initial stack pointer offset, in order to ; reduce the code size... ; -StackBuf equ STACK_TOP-44-32 ; Start the stack here (grow down - 4K) -PartInfo equ StackBuf ; Saved partition table entry -FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo) -OrigFDCTabPtr equ StackBuf-8 ; The 2nd high dword on the stack -OrigESDI equ StackBuf-4 ; The high dword on the stack -StackHome equ OrigFDCTabPtr ; The start of the canonical stack + +StackBuf equ STACK_TOP-44-92 ; Start the stack here (grow down - 4K) +PartInfo equ StackBuf +.mbr equ PartInfo +.gptlen equ PartInfo+16 +.gpt equ PartInfo+20 +FloppyTable equ PartInfo+76 +; Total size of PartInfo + FloppyTable == 76+16 = 92 bytes +Hidden equ StackBuf-20 ; Partition offset +OrigFDCTabPtr equ StackBuf-12 ; The 2nd high dword on the stack +OrigESDI equ StackBuf-8 ; The high dword on the stack +DriveNumber equ StackBuf-4 ; Drive number +StackHome equ Hidden ; The start of the canonical stack ; ; Primary entry point. Tempting as though it may be, we can't put the @@ -98,6 +99,7 @@ superblock_max equ $-superblock global SecPerClust SecPerClust equ bxSecPerClust + ; ; Note we don't check the constraints above now; we did that at install ; time (we hope!) @@ -108,20 +110,24 @@ start: ; ; Set up the stack ; - xor ax,ax - mov ss,ax - mov sp,StackBuf ; Just below BSS + xor cx,cx + mov ss,cx + mov sp,StackBuf-2 ; Just below BSS (-2 for alignment) + push dx ; Save drive number (in DL) push es ; Save initial ES:DI -> $PnP pointer push di - mov es,ax + mov es,cx + ; -; DS:SI may contain a partition table entry. Preserve it for us. +; DS:SI may contain a partition table entry and possibly a GPT entry. +; Preserve it for us. This saves 56 bytes of the GPT entry, which is +; currently the maximum we care about. Total is 76 bytes. ; - mov cx,8 ; Save partition info + mov cl,(16+4+56)/2 ; Save partition info mov di,PartInfo - rep movsw + rep movsw ; This puts CX back to zero - mov ds,ax ; Now we can initialize DS... + mov ds,cx ; Now we can initialize DS... ; ; Now sautee the BIOS floppy info block to that it will support decent- @@ -138,12 +144,12 @@ start: ; Save the old fdctab even if hard disk so the stack layout ; is the same. The instructions above do not change the flags - mov [DriveNumber],dl ; Save drive number in DL and dl,dl ; If floppy disk (00-7F), assume no ; partition table js harddisk floppy: + xor ax,ax mov cl,6 ; 12 bytes (CX == 0) ; es:di -> FloppyTable already ; This should be safe to do now, interrupts are off... @@ -151,26 +157,49 @@ floppy: mov [bx+2],ax ; Segment 0 fs rep movsw ; Faster to move words mov cl,[bsSecPerTrack] ; Patch the sector count - mov [di-8],cl - ; AX == 0 here - int 13h ; Some BIOSes need this + mov [di-76+8],cl + + push ax ; Partition offset == 0 + push ax + push ax + push ax + int 13h ; Some BIOSes need this jmp short not_harddisk ; ; The drive number and possibly partition information was passed to us ; by the BIOS or previous boot loader (MBR). Current "best practice" is to ; trust that rather than what the superblock contains. ; -; Would it be better to zero out bsHidden if we don't have a partition table? -; ; Note: di points to beyond the end of PartInfo ; harddisk: - test byte [di-16],7Fh ; Sanity check: "active flag" should - jnz no_partition ; be 00 or 80 - mov eax,[di-8] ; Partition offset (dword) - mov [bsHidden],eax -no_partition: + test byte [di-76],7Fh ; Sanity check: "active flag" should + jnz .no_partition ; be 00 or 80 + cmp [di-76+4],cl ; Sanity check: partition type != 0 + je .no_partition + cmp eax,'!GPT' ; !GPT signature? + jne .mbr + cmp byte [di-76+4],0EDh ; Synthetic GPT partition entry? + jne .mbr +.gpt: ; GPT-style partition info + push dword [di-76+20+36] + push dword [di-76+20+32] + jmp .gotoffs +.mbr: ; MBR-style partition info + push cx ; Upper half partition offset == 0 + push cx + push dword [di-76+8] ; Partition offset (dword) + jmp .gotoffs +.no_partition: +; +; No partition table given... assume that the Hidden field in the boot sector +; tells the truth (in particular, is zero if this is an unpartitioned disk.) +; + push cx + push cx + push dword [bsHidden] +.gotoffs: ; ; Get disk drive parameters (don't trust the superblock.) Don't do this for ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about @@ -211,7 +240,7 @@ eddcheck: ; ; We have EDD support... ; - mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2)) + mov byte [getonesec.jmp+1],(getonesec_ebios-(getonesec.jmp+2)) .noedd: ; @@ -219,7 +248,10 @@ eddcheck: ; with parsing the superblock and root directory; it doesn't fit ; together with EBIOS support, unfortunately. ; - mov eax,[FirstSector] ; Sector start + mov eax,strict dword 0xdeadbeef +Sect1Ptr0 equ $-4 + mov edx,strict dword 0xfeedface +Sect1Ptr1 equ $-4 mov bx,ldlinux_sys ; Where to load it call getonesec @@ -228,79 +260,46 @@ eddcheck: jne kaboom ; Go for it... - jmp ldlinux_ent + jmp 0:ldlinux_ent -; -; getonesec: get one disk sector -; -getonesec: - mov bp,1 ; One sector - ; Fall through ; -; getlinsec: load a sequence of BP floppy sector given by the linear sector -; number in EAX into the buffer at ES:BX. We try to optimize -; by loading up to a whole track at a time, but the user -; is responsible for not crossing a 64K boundary. -; (Yes, BP is weird for a count, but it was available...) +; getonesec: load a single disk linear sector EDX:EAX into the buffer +; at ES:BX. ; -; On return, BX points to the first byte after the transferred -; block. -; -; This routine assumes CS == DS, and trashes most registers. +; This routine assumes CS == DS == SS, and trashes most registers. ; ; Stylistic note: use "xchg" instead of "mov" when the source is a register ; that is dead from that point; this saves space. However, please keep ; the order to dst,src to keep things sane. ; - global getlinsec -getlinsec: - add eax,[bsHidden] ; Add partition offset - xor edx,edx ; Zero-extend LBA (eventually allow 64 bits) - -.jmp: jmp strict short getlinsec_cbios +getonesec: + add eax,[Hidden] ; Add partition offset + adc edx,[Hidden+4] + mov cx,retry_count +.jmp: jmp strict short getonesec_cbios ; -; getlinsec_ebios: +; getonesec_ebios: ; -; getlinsec implementation for EBIOS (EDD) +; getonesec implementation for EBIOS (EDD) ; -getlinsec_ebios: -.loop: - push bp ; Sectors left -.retry2: - call maxtrans ; Enforce maximum transfer size - movzx edi,bp ; Sectors we are about to read - mov cx,retry_count +getonesec_ebios: .retry: - ; Form DAPA on stack push edx push eax push es push bx - push di + push word 1 push word 16 mov si,sp pushad - mov dl,[DriveNumber] - push ds - push ss - pop ds ; DS <- SS mov ah,42h ; Extended Read - int 13h - pop ds + call xint13 popad lea sp,[si+16] ; Remove DAPA jc .error - pop bp - add eax,edi ; Advance sector pointer - sub bp,di ; Sectors left - shl di,SECTOR_SHIFT ; 512-byte sectors - add bx,di ; Advance buffer pointer - and bp,bp - jnz .loop - ret .error: @@ -311,32 +310,21 @@ getlinsec_ebios: pushad ; Try resetting the device xor ax,ax - mov dl,[DriveNumber] - int 13h + call xint13 popad loop .retry ; CX-- and jump if not zero - ;shr word [MaxTransfer],1 ; Reduce the transfer size - ;jnz .retry2 - ; Total failure. Try falling back to CBIOS. - mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2)) - ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer - - pop bp - ; ... fall through ... + mov byte [getonesec.jmp+1],(getonesec_cbios-(getonesec.jmp+2)) ; -; getlinsec_cbios: +; getonesec_cbios: ; ; getlinsec implementation for legacy CBIOS ; -getlinsec_cbios: -.loop: - push edx - push eax - push bp - push bx +getonesec_cbios: +.retry: + pushad movzx esi,word [bsSecPerTrack] movzx edi,word [bsHeads] @@ -351,25 +339,13 @@ getlinsec_cbios: ; eax = track # div edi ; Convert track to head/cyl - ; We should test this, but it doesn't fit... - ; cmp eax,1023 - ; ja .error + cmp eax,1023 ; Outside the CHS range? + ja kaboom ; ; Now we have AX = cyl, DX = head, CX = sector (0-based), - ; BP = sectors to transfer, SI = bsSecPerTrack, - ; ES:BX = data target + ; SI = bsSecPerTrack, ES:BX = data target ; - - call maxtrans ; Enforce maximum transfer size - - ; Must not cross track boundaries, so BP <= SI-CX - sub si,cx - cmp bp,si - jna .bp_ok - mov bp,si -.bp_ok: - shl ah,6 ; Because IBM was STOOPID ; and thought 8 bits were enough ; then thought 10 bits were enough... @@ -377,35 +353,14 @@ getlinsec_cbios: or cl,ah mov ch,al mov dh,dl - mov dl,[DriveNumber] - xchg ax,bp ; Sector to transfer count - mov ah,02h ; Read sectors - mov bp,retry_count -.retry: - pushad - int 13h + mov ax,0201h ; Read one sector + call xint13 popad jc .error -.resume: - movzx ecx,al ; ECX <- sectors transferred - shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX - pop bx - add bx,ax - pop bp - pop eax - pop edx - add eax,ecx - sub bp,cx - jnz .loop ret .error: - dec bp - jnz .retry - - xchg ax,bp ; Sectors transferred <- 0 - shr word [MaxTransfer],1 - jnz .resume + loop .retry ; Fall through to disk_error ; @@ -421,47 +376,51 @@ kaboom: pop dword [fdctab] ; Restore FDC table .patch: ; When we have full code, intercept here mov si,bailmsg + call writestr_early - ; Write error message, this assumes screen page 0 + xor ax,ax +.again: int 16h ; Wait for keypress + ; NB: replaced by int 18h if + ; chosen at install time.. + int 19h ; And try once more to boot... +.norge: hlt ; If int 19h returned; this is the end + jmp short .norge + +; +; +; writestr_early: write a null-terminated string to the console +; This assumes we're on page 0. This is only used for early +; messages, so it should be OK. +; +writestr_early: + pushad .loop: lodsb and al,al - jz .done + jz .return mov ah,0Eh ; Write to screen as TTY mov bx,0007h ; Attribute int 10h jmp short .loop -.done: - cbw ; AH <- 0 -.again: int 16h ; Wait for keypress - ; NB: replaced by int 18h if - ; chosen at install time.. - int 19h ; And try once more to boot... -.norge: jmp short .norge ; If int 19h returned; this is the end +.return: popad + ret ; -; Truncate BP to MaxTransfer +; INT 13h wrapper function ; -maxtrans: - cmp bp,[MaxTransfer] - jna .ok - mov bp,[MaxTransfer] -.ok: ret +xint13: + mov dl,[DriveNumber] + int 13h + ret ; ; Error message on failure ; bailmsg: db 'Boot error', 0Dh, 0Ah, 0 - ; This fails if the boot sector overflows - zb 1F8h-($-$$) + ; This fails if the boot sector overflowsg + zb 1FEh-($-$$) -FirstSector dd 0xDEADBEEF ; Location of sector 1 -MaxTransfer dw 0x007F ; Max transfer size - -; This field will be filled in 0xAA55 by the installer, but we abuse it -; to house a pointer to the INT 16h instruction at -; kaboom.again, which gets patched to INT 18h in RAID mode. -bootsignature dw kaboom.again-bootsec +bootsignature dw 0xAA55 ; ; =========================================================================== @@ -493,24 +452,41 @@ ADVSectors dw 0 ; Additional sectors for ADVs LDLDwords dd 0 ; Total dwords starting at ldlinux_sys, CheckSum dd 0 ; Checksum starting at ldlinux_sys ; value = LDLINUX_MAGIC - [sum of dwords] +MaxTransfer dw 127 ; Max sectors to transfer +EPAPtr dw EPA - LDLINUX_SYS ; Pointer to the extended patch area + +; +; Extended patch area -- this is in .data16 so it doesn't occupy space in +; the first sector. Use this structure for anything that isn't used by +; the first sector itself. +; + section .data16 + alignz 2 +EPA: +ADVSecPtr dw ADVSec0 - LDLINUX_SYS CurrentDirPtr dw CurrentDirName-LDLINUX_SYS ; Current directory name string CurrentDirLen dw CURRENTDIR_MAX SubvolPtr dw SubvolName-LDLINUX_SYS SubvolLen dw SUBVOL_MAX SecPtrOffset dw SectorPtrs-LDLINUX_SYS -SecPtrCnt dw (SectorPtrsEnd - SectorPtrs) >> 2 +SecPtrCnt dw (SectorPtrsEnd - SectorPtrs)/10 + +; +; Boot sector patch pointers +; +Sect1Ptr0Ptr dw Sect1Ptr0 - bootsec ; Pointers to Sector 1 location +Sect1Ptr1Ptr dw Sect1Ptr1 - bootsec +RAIDPatchPtr dw kaboom.again - bootsec ; Patch to INT 18h in RAID mode ; -; Installer pokes the base directory here. This is in .data16 so it -; isn't actually located in the first sector. +; Base directory name and subvolume, if applicable. ; %define HAVE_CURRENTDIRNAME - section .data16 global CurrentDirName, SubvolName CurrentDirName times CURRENTDIR_MAX db 0 SubvolName times SUBVOL_MAX db 0 - section .init + section .init ldlinux_ent: ; ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 @@ -519,8 +495,6 @@ ldlinux_ent: ; value in CS, but we don't want to deal with that anymore from now ; on. ; - jmp 0:.next -.next: sti ; In case of broken INT 13h BIOSes ; @@ -530,13 +504,26 @@ ldlinux_ent: call writestr_early ; +; Checksum data thus far +; + mov si,ldlinux_sys + mov cx,SECTOR_SIZE >> 2 + mov edx,-LDLINUX_MAGIC +.checksum: + lodsd + add edx,eax + loop .checksum + mov [CheckSum],edx ; Save intermediate result + +; ; Tell the user if we're using EBIOS or CBIOS ; print_bios: mov si,cbios_name - cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2)) + cmp byte [getonesec.jmp+1],(getonesec_ebios-(getonesec.jmp+2)) jne .cbios mov si,ebios_name + mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2)) .cbios: mov [BIOSName],si call writestr_early @@ -547,8 +534,7 @@ BIOSName resw 1 section .init ; -; Now we read the rest of LDLINUX.SYS. Don't bother loading the first -; sector again, though. +; Now we read the rest of LDLINUX.SYS. ; load_rest: lea esi,[SectorPtrs] @@ -558,37 +544,19 @@ load_rest: .get_chunk: jcxz .done - xor ebp,ebp - mov di,bx ; Low 64K of target address - lodsd ; First sector of this chunk - - mov edx,eax - -.make_chunk: - inc bp - dec cx - jz .chunk_ready - cmp ebx,esi ; Pointer we don't have yet? - jae .chunk_ready - inc edx ; Next linear sector - cmp [si],edx ; Does it match - jnz .chunk_ready ; If not, this is it - add si,4 ; If so, add sector to chunk - add di,SECTOR_SIZE ; Check for 64K segment wrap - jnz .make_chunk - -.chunk_ready: + mov eax,[si] + mov edx,[si+4] + movzx ebp,word [si+8] + sub cx,bp push ebx - push es shr ebx,4 ; Convert to a segment mov es,bx xor bx,bx - xor edx,edx ; Zero-extend LBA - call getlinsecsr - pop es + call getlinsec pop ebx shl ebp,SECTOR_SHIFT add ebx,ebp + add si,10 jmp .get_chunk .done: @@ -599,10 +567,10 @@ load_rest: ; by the time we get to the end it should all cancel out. ; verify_checksum: - mov si,ldlinux_sys + mov si,ldlinux_sys + SECTOR_SIZE mov ecx,[LDLDwords] - mov eax,-LDLINUX_MAGIC - push ds + sub ecx,SECTOR_SIZE >> 2 + mov eax,[CheckSum] .checksum: add eax,[si] add si,4 @@ -614,12 +582,7 @@ verify_checksum: .nowrap: dec ecx jnz .checksum - pop ds - push eax - mov si,cbios_name - call writestr_early - pop eax and eax,eax ; Should be zero jz all_read ; We're cool, go for it! @@ -635,37 +598,181 @@ verify_checksum: ; Subroutines that have to be in the first sector ; ----------------------------------------------------------------------------- + + ; +; getlinsec: load a sequence of BP floppy sector given by the linear sector +; number in EAX into the buffer at ES:BX. We try to optimize +; by loading up to a whole track at a time, but the user +; is responsible for not crossing a 64K boundary. +; (Yes, BP is weird for a count, but it was available...) ; -; writestr_early: write a null-terminated string to the console -; This assumes we're on page 0. This is only used for early -; messages, so it should be OK. +; On return, BX points to the first byte after the transferred +; block. ; -writestr_early: +; This routine assumes CS == DS. +; + global getlinsec +getlinsec: pushad -.loop: lodsb - and al,al - jz .return - mov ah,0Eh ; Write to screen as TTY - mov bx,0007h ; Attribute - int 10h - jmp short .loop -.return: popad - ret + add eax,[Hidden] ; Add partition offset + adc edx,[Hidden+4] +.jmp: jmp strict short getlinsec_cbios +; +; getlinsec_ebios: +; +; getlinsec implementation for EBIOS (EDD) +; +getlinsec_ebios: +.loop: + push bp ; Sectors left +.retry2: + call maxtrans ; Enforce maximum transfer size + movzx edi,bp ; Sectors we are about to read + mov cx,retry_count +.retry: + + ; Form DAPA on stack + push edx + push eax + push es + push bx + push di + push word 16 + mov si,sp + pushad + mov ah,42h ; Extended Read + push ds + push ss + pop ds + call xint13 + pop ds + popad + lea sp,[si+16] ; Remove DAPA + jc .error + pop bp + add eax,edi ; Advance sector pointer + adc edx,0 + sub bp,di ; Sectors left + shl di,SECTOR_SHIFT ; 512-byte sectors + add bx,di ; Advance buffer pointer + and bp,bp + jnz .loop + + popad + ret + +.error: + ; Some systems seem to get "stuck" in an error state when + ; using EBIOS. Doesn't happen when using CBIOS, which is + ; good, since some other systems get timeout failures + ; waiting for the floppy disk to spin up. + + pushad ; Try resetting the device + xor ax,ax + mov dl,[DriveNumber] + int 13h + popad + loop .retry ; CX-- and jump if not zero + + ;shr word [MaxTransfer],1 ; Reduce the transfer size + ;jnz .retry2 + + ; Total failure. Try falling back to CBIOS. + mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2)) + ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer + + pop bp + ; ... fall through ... ; -; getlinsecsr: save registers, call getlinsec, restore registers -; Save/restore the flags, too, especially IF. +; getlinsec_cbios: +; +; getlinsec implementation for legacy CBIOS ; -getlinsecsr: - pushfd +getlinsec_cbios: +.loop: + push edx + push eax + push bp + push bx + + movzx esi,word [bsSecPerTrack] + movzx edi,word [bsHeads] + ; + ; Dividing by sectors to get (track,sector): we may have + ; up to 2^18 tracks, so we need to use 32-bit arithmetric. + ; + div esi + xor cx,cx + xchg cx,dx ; CX <- sector index (0-based) + ; EDX <- 0 + ; eax = track # + div edi ; Convert track to head/cyl + + cmp eax,1023 ; Outside the CHS range? + ja kaboom + + ; + ; Now we have AX = cyl, DX = head, CX = sector (0-based), + ; BP = sectors to transfer, SI = bsSecPerTrack, + ; ES:BX = data target + ; + + call maxtrans ; Enforce maximum transfer size + + ; Must not cross track boundaries, so BP <= SI-CX + sub si,cx + cmp bp,si + jna .bp_ok + mov bp,si +.bp_ok: + + shl ah,6 ; Because IBM was STOOPID + ; and thought 8 bits were enough + ; then thought 10 bits were enough... + inc cx ; Sector numbers are 1-based, sigh + or cl,ah + mov ch,al + mov dh,dl + xchg ax,bp ; Sector to transfer count + mov ah,02h ; Read sectors + mov bp,retry_count +.retry: pushad - call getlinsec + call xint13 + popad + jc .error +.resume: + movzx ecx,al ; ECX <- sectors transferred + shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX + pop bx + add bx,ax + pop bp + pop eax + pop edx + add eax,ecx + sub bp,cx + jnz .loop popad - popfd ret +.error: + dec bp + jnz .retry + + xchg ax,bp ; Sectors transferred <- 0 + shr word [MaxTransfer],1 + jnz .resume + jmp kaboom + +maxtrans: + cmp bp,[MaxTransfer] + jna .ok + mov bp,[MaxTransfer] +.ok: ret + ; ; Checksum error message ; @@ -691,16 +798,22 @@ rl_checkpt equ $ ; Must be <= 8000h rl_checkpt_off equ ($-$$) %ifndef DEPEND -%if rl_checkpt_off > 3FCh ; Need one pointer in here -%error "Sector 1 overflow" -%endif + %if rl_checkpt_off > 3F6h ; Need one extent + %assign rl_checkpt_overflow rl_checkpt_off - 3F6h + %error Sector 1 overflow by rl_checkpt_overflow bytes + %endif %endif -; Sector pointers - alignz 4 +; +; Extent pointers... each extent contains an 8-byte LBA and an 2-byte +; sector count. In most cases, we will only ever need a handful of +; extents, but we have to assume a maximally fragmented system where each +; extent contains only one sector. +; + alignz 2 MaxInitDataSize equ 96 << 10 MaxLMA equ TEXT_START+SECTOR_SIZE+MaxInitDataSize -SectorPtrs times MaxInitDataSize >> SECTOR_SHIFT dd 0 +SectorPtrs zb 10*(MaxInitDataSize >> SECTOR_SHIFT) SectorPtrsEnd equ $ ; ---------------------------------------------------------------------------- @@ -708,18 +821,19 @@ SectorPtrsEnd equ $ ; ---------------------------------------------------------------------------- section .text16 -test_string db 'test', 0 ; temp add by feng - all_read: + ; We enter here with both DS and ES scrambled... + xor ax,ax + mov ds,ax + mov es,ax ; ; Let the user (and programmer!) know we got this far. This used to be ; in Sector 1, but makes a lot more sense here. ; - ;mov si,copyright_str - ;call writestr_early - - mov si,test_string + mov si,copyright_str call writestr_early + + ; ; Insane hack to expand the DOS superblock to dwords ; @@ -746,21 +860,16 @@ expand_super: mov eax,ROOT_FS_OPS movzx dx,byte [DriveNumber] ; DH = 0: we are boot from disk not CDROM - mov ecx,[bsHidden] - ; Reserved for upper 32 bits of partition offset... - ; mov ebx,[bsHidden+4] - xor ebx,ebx + mov ecx,[Hidden] + mov ebx,[Hidden+4] mov si,[bsHeads] mov di,[bsSecPerTrack] movzx ebp,word [MaxTransfer] - - ;mov si,ebios_name - ;call writestr_early - pm_call fs_init - - ;mov si,ebios_name - ;call writestr_early - pm_call load_env32 popad + + section .bss16 +SuperInfo resq 16 ; The first 16 bytes expanded 8 times + + section .text16 diff --git a/core/extlinux.asm b/core/extlinux.asm deleted file mode 100644 index 9538576..0000000 --- a/core/extlinux.asm +++ /dev/null @@ -1,38 +0,0 @@ -; -*- fundamental -*- (asm-mode sucks) -; **************************************************************************** -; -; extlinux.asm -; -; A program to boot Linux kernels off an ext2/ext3 filesystem. -; -; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved -; Copyright 2009 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. -; -; **************************************************************************** - -%define IS_EXTLINUX 1 -%include "head.inc" - -; -; Some semi-configurable constants... change on your own risk. -; -my_id equ extlinux_id - - section .rodata - alignz 4 -ROOT_FS_OPS: - extern vfat_fs_ops - dd vfat_fs_ops - extern ext2_fs_ops - dd ext2_fs_ops - extern btrfs_fs_ops - dd btrfs_fs_ops - dd 0 - -%include "diskfs.inc" diff --git a/core/include/core.h b/core/include/core.h index 3de2b4d..799c337 100644 --- a/core/include/core.h +++ b/core/include/core.h @@ -64,10 +64,14 @@ __noreturn _kaboom(void); /* * Basic timer function... */ -extern volatile uint32_t __jiffies; +extern volatile uint32_t __jiffies, __ms_timer; static inline uint32_t jiffies(void) { return __jiffies; } +static inline uint32_t ms_timer(void) +{ + return __ms_timer; +} #endif /* CORE_H */ diff --git a/core/isolinux.asm b/core/isolinux.asm index 8060767..1ef68d8 100644 --- a/core/isolinux.asm +++ b/core/isolinux.asm @@ -101,7 +101,7 @@ ISOFlags resb 1 ; Flags for ISO directory search RetryCount resb 1 ; Used for disk access retries alignb 8 -bsHidden resq 1 ; Used in hybrid mode +Hidden resq 1 ; Used in hybrid mode bsSecPerTrack resw 1 ; Used in hybrid mode bsHeads resw 1 ; Used in hybrid mode @@ -242,9 +242,6 @@ _start_hybrid: pop eax pop ebx .nooffset: - mov [cs:bsHidden],eax - mov [cs:bsHidden+4],ebx - mov si,bios_cbios jcxz _start_common mov si,bios_ebios @@ -253,21 +250,26 @@ _start_hybrid: _start1: mov si,bios_cdrom + xor eax,eax + xor ebx,ebx _start_common: mov [cs:InitStack],sp ; Save initial stack pointer mov [cs:InitStack+2],ss - xor ax,ax - mov ss,ax + xor cx,cx + mov ss,cx mov sp,StackBuf ; Set up stack push es ; Save initial ES:DI -> $PnP pointer push di - mov ds,ax - mov es,ax - mov fs,ax - mov gs,ax + mov ds,cx + mov es,cx + mov fs,cx + mov gs,cx sti cld + mov [Hidden],eax + mov [Hidden+4],ebx + mov [BIOSType],si mov eax,[si] mov [GetlinsecPtr],eax @@ -779,8 +781,8 @@ getlinsec_ebios: xor edx,edx shld edx,eax,2 shl eax,2 ; Convert to HDD sectors - add eax,[bsHidden] - adc edx,[bsHidden+4] + add eax,[Hidden] + adc edx,[Hidden+4] shl bp,2 .loop: @@ -852,7 +854,7 @@ getlinsec_ebios: getlinsec_cbios: xor edx,edx shl eax,2 ; Convert to HDD sectors - add eax,[bsHidden] + add eax,[Hidden] shl bp,2 .loop: @@ -1165,8 +1167,8 @@ init_fs: .hybrid: movzx ebp,word [MaxTransfer] .common: - mov ecx,[bsHidden] - mov ebx,[bsHidden+4] + mov ecx,[Hidden] + mov ebx,[Hidden+4] mov si,[bsHeads] mov di,[bsSecPerTrack] pm_call fs_init diff --git a/core/ldlinux.asm b/core/ldlinux.asm index 23540ea..f62f55b 100644 --- a/core/ldlinux.asm +++ b/core/ldlinux.asm @@ -35,6 +35,10 @@ my_id equ syslinux_id ROOT_FS_OPS: extern vfat_fs_ops dd vfat_fs_ops + extern ext2_fs_ops + dd ext2_fs_ops + extern btrfs_fs_ops + dd btrfs_fs_ops dd 0 %include "diskfs.inc" diff --git a/core/pmapi.c b/core/pmapi.c index 3313cea..4b1ccbb 100644 --- a/core/pmapi.c +++ b/core/pmapi.c @@ -19,6 +19,8 @@ const struct com32_pmapi pm_api_vector = { + .__pmapi_size = sizeof(struct com32_pmapi), + .lmalloc = pmapi_lmalloc, /* Allocate low memory */ .lfree = free, /* Free low memory */ @@ -32,4 +34,10 @@ const struct com32_pmapi pm_api_vector = .idle = __idle, .reset_idle = reset_idle, + + .chdir = chdir, + .getcwd = getcwd, + + .jiffies = &__jiffies, + .ms_timer = &__ms_timer, }; diff --git a/core/timer.inc b/core/timer.inc index 728812b..b01ff91 100644 --- a/core/timer.inc +++ b/core/timer.inc @@ -19,6 +19,9 @@ ;; about the BIOS_timer variable wrapping around at "midnight" and other ;; weird things. ;; +;; This also maintains a timer variable calibrated in milliseconds +;; (wraparound time = 49.7 days!) +;; section .text16 @@ -35,12 +38,20 @@ timer_cleanup: mov [BIOS_timer_hook],eax ret +; +; The specified frequency is 14.31818 MHz/12/65536; this turns out +; to be a period of 54.92542 ms, or 0x36.ece8(187c) hexadecimal. +; timer_irq: inc dword [cs:__jiffies] + add word [cs:__ms_timer_adj],0xece8 + adc dword [cs:__ms_timer],0x36 jmp 0:0 BIOS_timer_next equ $-4 section .data16 alignz 4 - global __jiffies -__jiffies dd 0 ; The actual timer variable + global __jiffies, __ms_timer +__jiffies dd 0 ; Clock tick timer +__ms_timer dd 0 ; Millisecond timer +__ms_timer_adj dw 0 ; Millisecond timer correction factor diff --git a/elf_gen_dep.sh b/elf_gen_dep.sh index 654f96d..306034a 100755 --- a/elf_gen_dep.sh +++ b/elf_gen_dep.sh @@ -4,7 +4,7 @@ # Round 1: get all the loacl and external symbols ####################################################### -for i in com32/elflink/modules/*.c32 core/extlinux.elf core/isolinux.elf core/pxelinux.elf +for i in com32/elflink/modules/*.c32 core/isolinux.elf core/pxelinux.elf do # module=$(echo $i | sed "s/^\(.*\).o$/\1/") -- 2.7.4