[FREELDR][NTOSKRNL][TOOLS]

- Delete unused files.
- Use extension LDS instead of LNK (Windows shortcut file) for LD linker scripts.

svn path=/trunk/; revision=55868
This commit is contained in:
Dmitry Gorbachev 2012-02-25 21:45:56 +00:00
parent aeac841aa8
commit 1550726927
33 changed files with 540 additions and 7742 deletions

View file

@ -54,7 +54,7 @@ list(APPEND FREELDR_COMMON_SOURCE
inifile/parse.c
mm/meminit.c
mm/mm.c
mm/heap_new.c
mm/heap.c
reactos/registry.c
reactos/arcname.c
reactos/archwsup.c
@ -90,11 +90,11 @@ if(ARCH MATCHES i386)
arch/i386/i386bug.c
arch/i386/i386disk.c
arch/i386/i386idt.c
arch/i386/i386pnp.cmake.S
arch/i386/i386pnp.S
arch/i386/i386rtl.c
arch/i386/i386trap.S
arch/i386/i386vid.c
arch/i386/linux.cmake.S
arch/i386/linux.S
arch/i386/machpc.c
arch/i386/mb.S
arch/i386/miscboot.c
@ -165,8 +165,8 @@ add_library(freeldr_pe SHARED ${FREELDR_BASE_SOURCE})
add_library(freeldr_pe_dbg SHARED EXCLUDE_FROM_ALL ${FREELDR_BASE_SOURCE})
if(NOT MSVC)
add_target_link_flags(freeldr_pe "-Wl,--strip-all,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk")
add_target_link_flags(freeldr_pe_dbg "-Wl,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk")
add_target_link_flags(freeldr_pe "-Wl,--strip-all,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
add_target_link_flags(freeldr_pe_dbg "-Wl,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
else()
add_target_link_flags(freeldr_pe "/ignore:4078 /ignore:4254 /DRIVER /FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text /SUBSYSTEM:BOOT_APPLICATION")
add_target_link_flags(freeldr_pe_dbg "/ignore:4078 /ignore:4254 /DRIVER /FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text /SUBSYSTEM:BOOT_APPLICATION")
@ -228,8 +228,8 @@ add_library(setupldr_pe SHARED ${FREELDR_BASE_SOURCE} ${SETUPLDR_SOURCE})
add_library(setupldr_pe_dbg SHARED EXCLUDE_FROM_ALL ${FREELDR_BASE_SOURCE} ${SETUPLDR_SOURCE})
if(NOT MSVC)
add_target_link_flags(setupldr_pe "-Wl,--strip-all,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk")
add_target_link_flags(setupldr_pe_dbg "-Wl,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk")
add_target_link_flags(setupldr_pe "-Wl,--strip-all,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
add_target_link_flags(setupldr_pe_dbg "-Wl,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
else()
add_target_link_flags(setupldr_pe "/ignore:4078 /ignore:4254 /DRIVER /FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text /SUBSYSTEM:BOOT_APPLICATION")
add_target_link_flags(setupldr_pe_dbg "/ignore:4078 /ignore:4254 /DRIVER /FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text /SUBSYSTEM:BOOT_APPLICATION")

View file

@ -1,511 +0,0 @@
/*
* FreeLoader
* Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.intel_syntax noprefix
#define HEX(y) 0x##y
#include <arch/pc/x86common.h>
#include <multiboot.h>
.code16
EXTERN(_RealEntryPoint)
cli
/* Setup segment registers */
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Setup a stack */
mov sp, word ptr ds:stack16
sti
/* Init pmode */
call switch_to_prot
.code32
/* Zero BootPartition */
xor eax, eax
mov dword ptr [_FrldrBootPartition], eax
/* Store the boot drive */
mov byte ptr [_FrldrBootDrive], dl
/* Store the boot partition */
mov byte ptr [_FrldrBootPartition], dh
call _EnableA20
/* Clean out bss */
xor eax, eax
mov edi, offset __bss_start__
mov ecx, offset __bss_end__ + 3
sub ecx, edi
shr ecx, 2
rep stosd
/* GO! */
push eax
call _BootMain
call switch_to_real
.code16
int HEX(19)
/* We should never get here */
stop:
jmp stop
nop
nop
/*
* Switches the processor to protected mode
* it destroys eax
*/
EXTERN(switch_to_prot)
.code16
cli /* None of these */
/* We don't know what values are currently */
/* in the segment registers. So we are */
/* going to reload them with sane values. */
/* Of course CS has to already be valid. */
/* We are currently in real-mode so we */
/* need real-mode segment values. */
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Get the return address off the stack */
pop word ptr ds:[code32ret]
/* Save 16-bit stack pointer */
mov word ptr ds:[stack16], sp
/* Load the GDT */
lgdt gdtptr
/* Load the IDT */
lidt i386idtptr
/* Enable Protected Mode */
mov eax, cr0
or eax, CR0_PE_SET
mov cr0, eax
/* Clear prefetch queue & correct CS */
//ljmp PMODE_CS, inpmode
jmp far ptr PMODE_CS:inpmode
.code32
inpmode:
/* Setup segment selectors */
mov ax, PMODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, dword ptr [stack32]
/* Put the return address back onto the stack */
push dword ptr [code32ret]
/* Now return in p-mode! */
ret
/*
* Switches the processor back to real mode
* it destroys eax
*/
EXTERN(switch_to_real)
.code32
/* We don't know what values are currently */
/* in the segment registers. So we are */
/* going to reload them with sane values. */
/* Of course CS has to already be valid. */
/* We are currently in protected-mode so we */
/* need protected-mode segment values. */
mov ax, PMODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Get the return address off the stack */
pop dword ptr [code16ret]
/* Save 32-bit stack pointer */
mov dword ptr [stack32], esp
/* jmp to 16-bit segment to set the limit correctly */
ljmp RMODE_CS, switch_to_real16
switch_to_real16:
.code16
/* Restore segment registers to correct limit */
mov ax, RMODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Disable Protected Mode */
mov eax, cr0
and eax, CR0_PE_CLR
mov cr0, eax
/* Clear prefetch queue & correct CS */
//ljmp $0, $inrmode
jmp far ptr 0:inrmode
inrmode:
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Clear out the high 16-bits of ESP */
/* This is needed because I have one */
/* machine that hangs when booted to dos if */
/* anything other than 0x0000 is in the high */
/* 16-bits of ESP. Even though real-mode */
/* code should only use SP and not ESP. */
xor esp, esp
mov sp, word ptr ds:[stack16]
/* Put the return address back onto the stack */
push word ptr ds:[code16ret]
/* Load IDTR with real mode value */
lidt rmode_idtptr
sti /* These are ok now */
/* Now return in r-mode! */
ret
/*
* Needed for enabling the a20 address line
*/
.code16
empty_8042:
.word 0x00eb,0x00eb // jmp $+2, jmp $+2
in al, HEX(64)
cmp al, HEX(ff) // legacy-free machine without keyboard
jz empty_8042_ret // controllers on Intel Macs read back 0xFF
test al, 2
jnz empty_8042
empty_8042_ret:
ret
/*
* Enable the A20 address line (to allow access to over 1mb)
*/
EXTERN(_EnableA20)
.code32
pusha
call switch_to_real
.code16
call empty_8042
mov al, HEX(D1) // command write
out HEX(64), al
call empty_8042
mov al, HEX(DF) // A20 on
out HEX(60), al
call empty_8042
call switch_to_prot
.code32
popa
ret
/*
* Disable the A20 address line
*/
EXTERN(_DisableA20)
.code32
pusha
call switch_to_real
.code16
call empty_8042
mov al, HEX(D1) // command write
out HEX(64), al
call empty_8042
mov al, HEX(DD) // A20 off
out HEX(60), al
call empty_8042
call switch_to_prot
.code32
popa
ret
/* Multiboot support
*
* Allows freeldr to be loaded as a "multiboot kernel" by
* other boot loaders like Grub
*/
#define MB_INFO_SIZE 90
#define MB_INFO_FLAGS_OFFSET 0
#define MB_INFO_BOOT_DEVICE_OFFSET 12
#define MB_INFO_COMMAND_LINE_OFFSET 16
#define CMDLINE_SIZE 256
/*
* We want to execute at 0x8000 (to be compatible with bootsector
* loading), but Grub only allows loading of multiboot kernels
* above 1MB. So we let Grub load us there and then relocate
* ourself to 0x8000
*/
#define FREELDR_BASE HEX(8000)
#define INITIAL_BASE HEX(200000)
/* Align 32 bits boundary */
.align 4
/* Multiboot header */
MultibootHeader:
/* magic */
.long MULTIBOOT_HEADER_MAGIC
/* flags */
.long MULTIBOOT_HEADER_FLAGS
/* checksum */
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
/* header_addr */
.long INITIAL_BASE + MultibootHeader - FREELDR_BASE
/* load_addr */
.long INITIAL_BASE
/* load_end_addr */
.long INITIAL_BASE + __bss_start__ - FREELDR_BASE
/* bss_end_addr */
.long INITIAL_BASE + __bss_end__ - FREELDR_BASE
/* entry_addr */
.long INITIAL_BASE + MultibootEntry - FREELDR_BASE
MultibootEntry:
cli /* Even after setting up the our IDT below we are
* not ready to handle hardware interrupts (no entries
* in IDT), so there's no sti here. Interrupts will be
* enabled in due time */
/* Although the multiboot spec says we should be called with the
* segment registers set to 4GB flat mode, let's be sure and set up
* our own */
lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
/* Reload segment selectors */
//ljmp $PMODE_CS, $(mb1 + INITIAL_BASE - FREELDR_BASE)
jmp far ptr PMODE_CS: (mb1 + INITIAL_BASE - FREELDR_BASE)
mb1:
mov dx, PMODE_DS
mov ds, dx
mov es, dx
/* Check for valid multiboot signature */
cmp eax, MULTIBOOT_BOOTLOADER_MAGIC
jne mbfail
/* Store multiboot info in a safe place */
mov esi, ebx
mov edi, offset mb_info + INITIAL_BASE - FREELDR_BASE
mov ecx, MB_INFO_SIZE
rep movsb
/* Save commandline */
mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
jz mb3
mov esi, [ebx + MB_INFO_COMMAND_LINE_OFFSET]
mov edi, offset cmdline + INITIAL_BASE - FREELDR_BASE
mov ecx, CMDLINE_SIZE
mb2: lodsb
stosb
test al, al
jz mb3
dec ecx
jnz mb2
mb3:
/* Copy to low mem */
mov esi, INITIAL_BASE
mov edi, FREELDR_BASE
mov ecx, (offset __bss_end__ - FREELDR_BASE)
add ecx, 3
shr ecx, 2
rep movsd
/* Load the GDT and IDT */
lgdt gdtptr
lidt i386idtptr
/* Clear prefetch queue & correct CS,
* jump to low mem */
//ljmp $PMODE_CS, $mb4
jmp far ptr PMODE_CS:mb4
mb4:
/* Reload segment selectors */
mov dx, PMODE_DS
mov ds, dx
mov es, dx
mov fs, dx
mov gs, dx
mov ss, dx
mov esp, STACK32ADDR
mov ebx, offset mb_info
/* See if the boot device was passed in */
mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
test edx, MB_INFO_FLAG_BOOT_DEVICE
jz mb5
/* Retrieve boot device info */
mov eax, [ebx + MB_INFO_BOOT_DEVICE_OFFSET]
shr eax, 16
inc al
mov byte ptr _FrldrBootPartition, al
mov byte ptr _FrldrBootDrive, ah
jmp mb6
mb5: /* No boot device known, assume first partition of first harddisk */
mov byte ptr _FrldrBootDrive, HEX(80)
mov byte ptr _FrldrBootPartition, 1
mb6:
/* Check for command line */
mov eax, offset cmdline
test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
jnz mb7
xor eax, eax
mb7:
/* GO! */
push eax
call _BootMain
mbfail:
call switch_to_real
.code16
int 0x19
mbstop: jmp mbstop /* We should never get here */
.code32
/* 16-bit stack pointer */
stack16:
.word STACK16ADDR
/* 32-bit stack pointer */
stack32:
.long STACK32ADDR
/* 16-bit return address */
code16ret:
.long 0
/* 32-bit return address */
code32ret:
.long 0
.align 4 /* force 4-byte alignment */
gdt:
/* NULL Descriptor */
.word HEX(0000)
.word HEX(0000)
.word HEX(0000)
.word HEX(0000)
/* 32-bit flat CS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9A00)
.word HEX(00CF)
/* 32-bit flat DS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9200)
.word HEX(00CF)
/* 16-bit real mode CS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9E00)
.word HEX(0000)
/* 16-bit real mode DS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9200)
.word HEX(0000)
/* GDT table pointer */
gdtptr:
.word HEX(27) /* Limit */
.long gdt /* Base Address */
/* Initial GDT table pointer for multiboot */
gdtptrhigh:
.word HEX(27) /* Limit */
.long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
/* Real-mode IDT pointer */
rmode_idtptr:
.word HEX(3ff) /* Limit */
.long 0 /* Base Address */
mb_info:
.fill MB_INFO_SIZE, 1, 0
cmdline:
.fill CMDLINE_SIZE, 1, 0
EXTERN(_FrldrBootDrive)
.byte 0
EXTERN(_FrldrBootPartition)
.long 0

View file

@ -1,60 +0,0 @@
/*
* FreeLoader
* Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.text
.code16
#include <arch/pc/x86common.h>
EXTERN(_ChainLoadBiosBootSectorCode)
.code32
call switch_to_real
.code16
/* Set the boot drive */
movb (_FrldrBootDrive),%dl
/* Load segment registers */
cli
movw $0x0000,%bx
movw %bx,%ds
movw %bx,%es
movw %bx,%fs
movw %bx,%gs
movw %bx,%ss
movw $0x7C00,%sp
ljmpl $0x0000,$0x7C00
EXTERN(_SoftReboot)
.code32
call switch_to_real
.code16
movw $0x40,%ax
movw %ax,%ds
movw $0x72,%si
// Set the word at location 40:72 to 1234h
movw $0x1234,(%si)
// and jump to location FFFF:0 in ROM
ljmpl $0xFFFF,$0x0000

View file

@ -1,241 +0,0 @@
// fathelp.S
// FAT12/16 Boot Sector Helper Code
// Copyright (c) 1998, 2001, 2002, 2003 Brian Palmer
#include <asm.inc>
//org 8000h
//.text
.code16
#define BootSectorStackTop HEX(7bf2)
#define DataAreaStartHigh 2
#define DataAreaStartLow 4
#define BiosCHSDriveSizeHigh 6
#define BiosCHSDriveSizeLow 8
#define BiosCHSDriveSize 8
#define ReadSectorsOffset 10
#define ReadClusterOffset 12
#define PutCharsOffset 14
#define OEMName 3
#define BytesPerSector 11
#define SectsPerCluster 13
#define ReservedSectors 14
#define NumberOfFats 16
#define MaxRootEntries 17
#define TotalSectors 19
#define MediaDescriptor 21
#define SectorsPerFat 22
#define SectorsPerTrack 24
#define NumberOfHeads 26
#define HiddenSectors 28
#define TotalSectorsBig 32
#define BootDrive 36
#define Reserved 37
#define ExtendSig 38
#define SerialNumber 39
#define VolumeLabel 43
#define FileSystem 54
#define BootPartition HEX(7dfd)
// This code will be stored in the first 512 bytes
// of freeldr.sys. The first 3 bytes will be a jmp
// instruction to skip past the FAT helper code
// that is stored in the rest of the 512 bytes.
//
// This code is loaded at 0000:8000 so we have to
// encode a jmp instruction to jump to 0000:8200
PUBLIC _mainCRTStartup // For Mingw32 builds where the linker looks for this symbol
_mainCRTStartup:
PUBLIC start
start:
#if 0
.byte HEX(e9)
.byte HEX(fd)
.byte HEX(01)
// Now starts the extra boot code that we will store
// in the first 512 bytes of freeldr.sys. This code
// allows the FAT12/16 bootsector to navigate the
// FAT table so that we can still load freeldr.sys
// even if it is fragmented.
FatHelperEntryPoint:
push ax // First save AX - the start cluster of freeldr.sys
// Display "Loading FreeLoader..." message
mov esi, offset msgLoading // Loading message
call word ptr [bp-PutCharsOffset] // Display it
call ReadFatIntoMemory
pop ax // Restore AX (start cluster)
// AX has start cluster of freeldr.sys
mov bx, HEX(800)
mov es,bx
LoadFile:
push ax
call IsFat12
pop ax
jnc LoadFile2
cmp ax, HEX(0ff8) // Check to see if this is the last cluster in the chain
jmp LoadFile3
LoadFile2:
cmp ax, HEX(0fff8)
LoadFile3:
jae LoadFile_Done // If so continue, if not then read then next one
push ax
xor bx,bx // Load ROSLDR starting at 0000:8000h
push es
call word ptr [bp-ReadClusterOffset]
pop es
xor bx,bx
mov bl, [bp+SectsPerCluster]
shl bx,5 // BX = BX * 512 / 16
mov ax,es // Increment the load address by
add ax,bx // The size of a cluster
mov es,ax
call IsFat12
pop ax
push es
jnc LoadFile4
call GetFatEntry12 // Get the next entry
jmp LoadFile5
LoadFile4:
call GetFatEntry16
LoadFile5:
pop es
jmp LoadFile // Load the next cluster (if any)
LoadFile_Done:
mov dl, byte ptr [bp+BootDrive] // Load the boot drive into DL
mov dh, byte ptr ds:[BootPartition] // Load the boot partition into DH
push 0 // push segment (0x0000)
mov bx, ds: [HEX(8000) + HEX(A8)] // load the RVA of the EntryPoint into eax
add bx, HEX(8000) // RVA -> VA and skip 3 bytes (jump to fathelper code)
push bx // push offset
retf // Transfer control to FreeLoader
// Reads the entire FAT into memory at 7000:0000
ReadFatIntoMemory:
mov ax, [bp+HiddenSectors]
mov dx, [bp+HiddenSectors+2]
add ax, [bp+ReservedSectors]
adc dx, 0
mov cx, [bp+SectorsPerFat]
mov bx, HEX(7000)
mov es,bx
xor bx,bx
call word ptr [bp-ReadSectorsOffset]
ret
// Returns the FAT entry for a given cluster number for 16-bit FAT
// On entry AX has cluster number
// On return AX has FAT entry for that cluster
GetFatEntry16:
mov cx,2 // AX = AX * 2 (since FAT16 entries are 2 bytes)
mul cx
shl dx,12
mov bx, HEX(7000)
add bx,dx
mov es,bx
mov bx,ax // Restore FAT entry offset
mov ax, es:[bx] // Get FAT entry
ret
// Returns the FAT entry for a given cluster number for 12-bit FAT
// On entry AX has cluster number
// On return AX has FAT entry for that cluster
GetFatEntry12:
push ax
mov cx,ax
shr ax,1
add ax,cx // AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits)
mov bx, HEX(7000)
mov es,bx
mov bx,ax // Put FAT entry offset into BX
mov ax, es:[bx] // Get FAT entry
pop cx // Get cluster number from stack
and cx,1
jz UseLow12Bits
and ax, HEX(0fff0)
shr ax,4
jmp GetFatEntry12_Done
UseLow12Bits:
and ax, HEX(0fff)
GetFatEntry12_Done:
ret
// Returns CF = 1 if this is a FAT12 file system
// Otherwise CF = 0 for FAT16
IsFat12:
mov ebx, dword ptr [bp-DataAreaStartLow]
// EBX now has the number of the starting sector of the data area
// starting from the beginning of the disk, so subtrace hidden sectors
sub ebx, dword ptr [bp+HiddenSectors]
xor eax,eax
mov ax, word ptr [bp+TotalSectors]
cmp ax, 0
jnz IsFat12_2
mov eax, dword ptr [bp+TotalSectorsBig]
// EAX now contains the number of sectors on the volume
IsFat12_2:
sub eax,ebx // Subtract data area start sector
xor edx,edx // from total sectors of volume
// EDX:EAX now contains the number of data sectors on the volume
movzx ebx, byte ptr [bp+SectsPerCluster]
div ebx
// EAX now has the number of clusters on the volume
stc
cmp eax,4085
jb IsFat12_Done
clc
IsFat12_Done:
ret
msgLoading: .asciz "Loading FreeLoader...\r\n"
.org HEX(1fe) // Pad to 510 bytes
.word HEX(0aa55) // BootSector signature
#endif
.endcode16
END

View file

@ -1,235 +0,0 @@
; FATHELP.ASM
; FAT12/16 Boot Sector Helper Code
; Copyright (c) 1998, 2001, 2002, 2003 Brian Palmer
;org 8000h
segment .text
bits 16
BootSectorStackTop equ 0x7bf2
DataAreaStartHigh equ 0x2
DataAreaStartLow equ 0x4
BiosCHSDriveSizeHigh equ 0x6
BiosCHSDriveSizeLow equ 0x8
BiosCHSDriveSize equ 0x8
ReadSectorsOffset equ 0xa
ReadClusterOffset equ 0xc
PutCharsOffset equ 0xe
OEMName equ 3
BytesPerSector equ 11
SectsPerCluster equ 13
ReservedSectors equ 14
NumberOfFats equ 16
MaxRootEntries equ 17
TotalSectors equ 19
MediaDescriptor equ 21
SectorsPerFat equ 22
SectorsPerTrack equ 24
NumberOfHeads equ 26
HiddenSectors equ 28
TotalSectorsBig equ 32
BootDrive equ 36
Reserved equ 37
ExtendSig equ 38
SerialNumber equ 39
VolumeLabel equ 43
FileSystem equ 54
BootPartition equ 0x7dfd
; This code will be stored in the first 512 bytes
; of freeldr.sys. The first 3 bytes will be a jmp
; instruction to skip past the FAT helper code
; that is stored in the rest of the 512 bytes.
;
; This code is loaded at 0000:8000 so we have to
; encode a jmp instruction to jump to 0000:8200
global _mainCRTStartup ; For Mingw32 builds where the linker looks for this symbol
_mainCRTStartup:
global start
start:
db 0xe9
db 0xfd
db 0x01
; Now starts the extra boot code that we will store
; in the first 512 bytes of freeldr.sys. This code
; allows the FAT12/16 bootsector to navigate the
; FAT table so that we can still load freeldr.sys
; even if it is fragmented.
FatHelperEntryPoint:
push ax ; First save AX - the start cluster of freeldr.sys
; Display "Loading FreeLoader..." message
mov esi,msgLoading ; Loading message
call [bp-PutCharsOffset] ; Display it
call ReadFatIntoMemory
pop ax ; Restore AX (start cluster)
; AX has start cluster of freeldr.sys
mov bx,800h
mov es,bx
LoadFile:
push ax
call IsFat12
pop ax
jnc LoadFile2
cmp ax,0ff8h ; Check to see if this is the last cluster in the chain
jmp LoadFile3
LoadFile2:
cmp ax,0fff8h
LoadFile3:
jae LoadFile_Done ; If so continue, if not then read then next one
push ax
xor bx,bx ; Load ROSLDR starting at 0000:8000h
push es
call [bp-ReadClusterOffset]
pop es
xor bx,bx
mov bl,BYTE [BYTE bp+SectsPerCluster]
shl bx,5 ; BX = BX * 512 / 16
mov ax,es ; Increment the load address by
add ax,bx ; The size of a cluster
mov es,ax
call IsFat12
pop ax
push es
jnc LoadFile4
call GetFatEntry12 ; Get the next entry
jmp LoadFile5
LoadFile4:
call GetFatEntry16
LoadFile5:
pop es
jmp LoadFile ; Load the next cluster (if any)
LoadFile_Done:
mov dl,BYTE [BYTE bp+BootDrive] ; Load the boot drive into DL
mov dh,[BootPartition] ; Load the boot partition into DH
push 0 ; push segment (0x0000)
mov bx, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax
add bx, 0x8000 ; RVA -> VA and skip 3 bytes (jump to fathelper code)
push bx ; push offset
retf ; Transfer control to FreeLoader
; Reads the entire FAT into memory at 7000:0000
ReadFatIntoMemory:
mov ax,WORD [BYTE bp+HiddenSectors]
mov dx,WORD [BYTE bp+HiddenSectors+2]
add ax,WORD [BYTE bp+ReservedSectors]
adc dx,byte 0
mov cx,WORD [BYTE bp+SectorsPerFat]
mov bx,7000h
mov es,bx
xor bx,bx
call [bp-ReadSectorsOffset]
ret
; Returns the FAT entry for a given cluster number for 16-bit FAT
; On entry AX has cluster number
; On return AX has FAT entry for that cluster
GetFatEntry16:
mov cx,2 ; AX = AX * 2 (since FAT16 entries are 2 bytes)
mul cx
shl dx,12
mov bx,7000h
add bx,dx
mov es,bx
mov bx,ax ; Restore FAT entry offset
mov ax,WORD [es:bx] ; Get FAT entry
ret
; Returns the FAT entry for a given cluster number for 12-bit FAT
; On entry AX has cluster number
; On return AX has FAT entry for that cluster
GetFatEntry12:
push ax
mov cx,ax
shr ax,1
add ax,cx ; AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits)
mov bx,7000h
mov es,bx
mov bx,ax ; Put FAT entry offset into BX
mov ax,WORD [es:bx] ; Get FAT entry
pop cx ; Get cluster number from stack
and cx,1
jz UseLow12Bits
and ax,0fff0h
shr ax,4
jmp GetFatEntry12_Done
UseLow12Bits:
and ax,0fffh
GetFatEntry12_Done:
ret
; Returns CF = 1 if this is a FAT12 file system
; Otherwise CF = 0 for FAT16
IsFat12:
mov ebx,DWORD [BYTE bp-DataAreaStartLow]
; EBX now has the number of the starting sector of the data area
; starting from the beginning of the disk, so subtrace hidden sectors
sub ebx,DWORD [BYTE bp+HiddenSectors]
xor eax,eax
mov ax,WORD [BYTE bp+TotalSectors]
cmp ax,byte 0
jnz IsFat12_2
mov eax,DWORD [BYTE bp+TotalSectorsBig]
; EAX now contains the number of sectors on the volume
IsFat12_2:
sub eax,ebx ; Subtract data area start sector
xor edx,edx ; from total sectors of volume
; EDX:EAX now contains the number of data sectors on the volume
movzx ebx,BYTE [BYTE bp+SectsPerCluster]
div ebx
; EAX now has the number of clusters on the volume
stc
cmp eax,4085
jb IsFat12_Done
clc
IsFat12_Done:
ret
msgLoading db 'Loading FreeLoader...',0dh,0ah,0
times 510-($-$$) db 0 ; Pad to 510 bytes
dw 0aa55h ; BootSector signature

View file

@ -1,129 +0,0 @@
/*
* FreeLoader
* Copyright (C) 2003 Eric Kohl
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.text
.code16
#include <arch/pc/x86common.h>
/*
* U32 CpuidSupported(VOID);
*
* RETURNS:
* 0x00000001: CPU supports the CPUID instruction
* 0x00000300: Found 80386 CPU
* 0x00000400: Found 80486 CPU without CPUID support
*/
EXTERN(_CpuidSupported)
.code32
pushl %ecx /* save ECX */
pushfl /* push original EFLAGS */
popl %eax /* get original EFLAGS */
movl %eax,%ecx /* save original EFLAGS */
xorl $0x40000,%eax /* flip AC bit in EFLAGS */
pushl %eax /* save new EFLAGS value on stack */
popfl /* replace current EFLAGS value */
pushfl /* get new EFLAGS */
popl %eax /* store new EFLAGS in EAX */
xorl %ecx, %eax /* can't toggle AC bit, processor=80386 */
movl $0x300,%eax /* return processor id */
jz NoCpuid /* jump if 80386 processor */
pushl %ecx
popfl /* restore AC bit in EFLAGS first */
movl %ecx,%eax /* get original EFLAGS */
xorl $0x200000,%eax /* flip ID bit in EFLAGS */
pushl %eax /* save new EFLAGS value on stack */
popfl /* replace current EFLAGS value */
pushfl /* get new EFLAGS */
popl %eax /* store new EFLAGS in EAX */
xorl %ecx,%eax /* can't toggle ID bit, */
movl $0x400,%eax /* return processor id */
je NoCpuid /* processor=80486 */
movl $1,%eax /* CPUID supported */
NoCpuid:
pushl %ecx
popfl /* restore EFLAGS */
popl %ecx /* retore ECX */
ret
/*
* VOID GetCpuid(U32 Level, U32 *eax, U32 *ebx, U32 *ecx, U32 *edx);
*/
EXTERN(_GetCpuid)
.code32
pushl %ebp
movl %esp,%ebp
pushl %eax
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
movl 0x08(%ebp),%eax
cpuid
movl 0x0C(%ebp),%esi
movl %eax,(%esi)
movl 0x10(%ebp),%esi
movl %ebx,(%esi)
movl 0x14(%ebp),%esi
movl %ecx,(%esi)
movl 0x18(%ebp),%esi
movl %edx,(%esi)
popl %esi
popl %edx
popl %ecx
popl %ebx
popl %eax
movl %ebp,%esp
popl %ebp
ret
/*
* U64 RDTSC(VOID);
*/
EXTERN(_RDTSC)
.code32
rdtsc
ret
/* EOF */

View file

@ -1,223 +0,0 @@
/*
* FreeLoader
* Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.text
.code16
#include <arch/pc/x86common.h>
.p2align 2 /* force 4-byte alignment */
EXTERN(i386idt)
/* Exception 0 - Divide By Zero */
.word _i386DivideByZero /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Flags, Zero Byte */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 1 - Debug Exception */
.word _i386DebugException /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 2 - NMI */
.word _i386NMIException /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 3 - Breakpoint (INT 3) */
.word _i386Breakpoint /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 4 - Overflow (INTO with EFLAGS[OF] set) */
.word _i386Overflow /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 5 - Bound Exception */
.word _i386BoundException /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 6 - Invalid Opcode */
.word _i386InvalidOpcode /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 7 - FPU Not Available */
.word _i386FPUNotAvailable /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 8 - Double Fault */
.word _i386DoubleFault /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 9 - Coprocessor Segment Overrun */
.word _i386CoprocessorSegment /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 10 (0x0A) - Invalid TSS */
.word _i386InvalidTSS /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 11 (0x0B) - Segment Not Present */
.word _i386SegmentNotPresent /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 12 (0x0C) - Stack Exception */
.word _i386StackException /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 13 (0x0D) - General Protection Fault */
.word _i386GeneralProtectionFault /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 14 (0x0E) - Page Fault */
.word _i386PageFault /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 15 (0x0F) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 16 (0x10) - Coprocessor Error */
.word _i386CoprocessorError /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 17 (0x11) - Alignment Check */
.word _i386AlignmentCheck /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 18 (0x12) - Machine Check */
.word _i386MachineCheck /* Offset 0 - 15 */
.word 0x0008 /* Selector */
.word 0x8e00 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 19 (0x13) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 20 (0x14) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 21 (0x15) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 22 (0x16) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 23 (0x17) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 24 (0x18) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 25 (0x19) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 26 (0x1A) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 27 (0x1B) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 28 (0x1C) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 29 (0x1D) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 30 (0x1E) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* Exception 31 (0x1F) - Reserved */
.word 0x0000 /* Offset 0 - 15 */
.word 0x0000 /* Selector */
.word 0x0000 /* Zero byte, flags */
.word 0x0000 /* Offset 16 - 31 */
/* IDT table pointer */
EXTERN(i386idtptr)
.word (i386idtptr - i386idt - 1) /* Limit */
.long i386idt /* Base Address */

View file

@ -20,19 +20,15 @@
#include <asm.inc>
#include <arch/pc/x86common.h>
.code32
EXTERN i386CallRealMode:PROC
.code32
/*
* U32 PnpBiosSupported(VOID);
*
* RETURNS:
*/
_pnp_bios_entry_point:
.long 0
_pnp_bios_data_segment:
.word 0
PUBLIC _PnpBiosSupported
_PnpBiosSupported:
@ -79,14 +75,14 @@ pnp_loop:
/* Calculate the bios entry point (far pointer) */
xor eax, eax
mov ax, [esi + 15]
mov ax, [esi + HEX(0F)]
shl eax, 16
mov ax, [esi + 0x0D]
mov _pnp_bios_entry_point, eax
mov ax, [esi + HEX(0D)]
mov dword ptr ds:[BSS_PnpBiosEntryPoint], eax
/* Store bios data segment */
mov ax, [esi + 0x1B]
mov _pnp_bios_data_segment, ax
mov ax, [esi + HEX(1B)]
mov word ptr ds:[BSS_PnpBiosDataSegment], ax
pnp_not_found:
mov eax, edi
@ -104,13 +100,6 @@ pnp_not_found:
*
* RETURNS:
*/
_pnp_result:
.long 0
_pnp_node_size:
.word 0
_pnp_node_count:
.word 0
PUBLIC _PnpBiosGetDeviceNodeCount
_PnpBiosGetDeviceNodeCount:
@ -120,41 +109,18 @@ _PnpBiosGetDeviceNodeCount:
pusha
push es
call switch_to_real
.code16
mov ax, word ptr [_pnp_bios_data_segment]
push ax
push cs
mov ax, offset _pnp_node_size
push ax
push cs
mov ax, offset _pnp_node_count
push ax
push 0
call dword ptr [_pnp_bios_entry_point]
add sp, 12
movzx ecx, ax
mov _pnp_result, ecx
call switch_to_prot
.code32
mov bx, FNID_PnpBiosGetDeviceNodeCount
call i386CallRealMode
mov esi, [ebp + 8]
mov ax, _pnp_node_size
mov ax, [BSS_PnpNodeSize]
movzx ecx, ax
mov [esi], ecx
mov esi, [ebp + 12]
mov ax, _pnp_node_count
mov ax, [BSS_PnpNodeCount]
movzx ecx, ax
mov [esi], eax
mov [esi], ecx
pop es
popa
@ -162,7 +128,7 @@ _PnpBiosGetDeviceNodeCount:
mov esp, ebp
pop ebp
mov eax, _pnp_result
mov eax, dword ptr [BSS_PnpResult]
ret
@ -172,16 +138,8 @@ _PnpBiosGetDeviceNodeCount:
*
* RETURNS:
*/
_pnp_buffer_segment:
.word 0
_pnp_buffer_offset:
.word 0
_pnp_node_number:
.byte 0
EXTERN(_PnpBiosGetDeviceNode)
.code32
PUBLIC _PnpBiosGetDeviceNode
_PnpBiosGetDeviceNode:
push ebp
mov ebp, esp
@ -192,54 +150,23 @@ EXTERN(_PnpBiosGetDeviceNode)
/* get current node number */
mov esi, [ebp + 8]
mov al, [esi]
mov _pnp_node_number, al
mov byte ptr ds:[BSS_PnpNodeNumber], al
/* convert pointer to node buffer to segment/offset */
mov eax, [ebp + 12]
shr eax, 4
and eax, 0xf000
mov _pnp_buffer_segment, ax
and eax, HEX(0f000)
mov word ptr ds:[BSS_PnpBiosBufferSegment], ax
mov eax, [ebp + 12]
and eax, 0xffff
mov _pnp_buffer_offset, ax
and eax, HEX(0ffff)
mov word ptr ds:[BSS_PnpBiosBufferOffset], ax
call switch_to_real
.code16
/* push bios segment */
mov ax, word ptr [_pnp_bios_data_segment]
push ax
/* push control flag */
push 1
/* push pointer to node buffer (segment/offset) */
mov ax, word ptr [_pnp_buffer_segment]
push ax
mov ax, word ptr [_pnp_buffer_offset]
push ax
/* push pointer to node number (segment/offset) */
push cs
mov ax, offset _pnp_node_number
push ax
/* push function number */
push 1
/* call entry point */
call dword ptr [_pnp_bios_entry_point]
add sp, 14
movzx ecx, ax
mov _pnp_result, ecx
call switch_to_prot
.code32
mov bx, FNID_PnpBiosGetDeviceNode
call i386CallRealMode
/* update node number */
mov esi, [ebp + 8]
mov al, _pnp_node_number
mov al, byte ptr ds:[BSS_PnpNodeNumber]
mov [esi], al
pop es
@ -248,8 +175,9 @@ EXTERN(_PnpBiosGetDeviceNode)
mov esp, ebp
pop ebp
mov eax, _pnp_result
mov eax, [BSS_PnpResult]
ret
END
/* EOF */

View file

@ -1,183 +0,0 @@
/*
* FreeLoader
* Copyright (C) 2003 Eric Kohl
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <asm.inc>
#include <arch/pc/x86common.h>
EXTERN i386CallRealMode:PROC
.code32
/*
* U32 PnpBiosSupported(VOID);
*
* RETURNS:
*/
PUBLIC _PnpBiosSupported
_PnpBiosSupported:
push edi
push esi
push ecx
push edx
xor edi, edi
/* init esi */
mov esi, HEX(0F0000)
pnp_again:
mov eax, [esi]
cmp eax, HEX(506E5024) /* "$PnP" */
je pnp_found
cmp esi, HEX(0FFFF0)
je pnp_not_found
pnp_add:
add esi, 16
jmp pnp_again
pnp_found:
/* first calculate the checksum */
push esi
push HEX(21)
pop ecx
xor edx, edx
pnp_loop:
lodsb
add dl, al
loop pnp_loop
test dl, dl
pop esi
jnz pnp_add
mov edi, esi
/* Calculate the bios entry point (far pointer) */
xor eax, eax
mov ax, [esi + HEX(0F)]
shl eax, 16
mov ax, [esi + HEX(0D)]
mov dword ptr ds:[BSS_PnpBiosEntryPoint], eax
/* Store bios data segment */
mov ax, [esi + HEX(1B)]
mov word ptr ds:[BSS_PnpBiosDataSegment], ax
pnp_not_found:
mov eax, edi
pop edx
pop ecx
pop esi
pop edi
ret
/*
* U32 PnpBiosGetDeviceNodeCount(U32 *NodeSize, U32 *NodeCount);
*
* RETURNS:
*/
PUBLIC _PnpBiosGetDeviceNodeCount
_PnpBiosGetDeviceNodeCount:
push ebp
mov ebp, esp
pusha
push es
mov bx, FNID_PnpBiosGetDeviceNodeCount
call i386CallRealMode
mov esi, [ebp + 8]
mov ax, [BSS_PnpNodeSize]
movzx ecx, ax
mov [esi], ecx
mov esi, [ebp + 12]
mov ax, [BSS_PnpNodeCount]
movzx ecx, ax
mov [esi], ecx
pop es
popa
mov esp, ebp
pop ebp
mov eax, dword ptr [BSS_PnpResult]
ret
/*
* U32 PnpBiosGetDeviceNode(U8 *NodeId, U8 *NodeBuffer);
*
* RETURNS:
*/
PUBLIC _PnpBiosGetDeviceNode
_PnpBiosGetDeviceNode:
push ebp
mov ebp, esp
pusha
push es
/* get current node number */
mov esi, [ebp + 8]
mov al, [esi]
mov byte ptr ds:[BSS_PnpNodeNumber], al
/* convert pointer to node buffer to segment/offset */
mov eax, [ebp + 12]
shr eax, 4
and eax, HEX(0f000)
mov word ptr ds:[BSS_PnpBiosBufferSegment], ax
mov eax, [ebp + 12]
and eax, HEX(0ffff)
mov word ptr ds:[BSS_PnpBiosBufferOffset], ax
mov bx, FNID_PnpBiosGetDeviceNode
call i386CallRealMode
/* update node number */
mov esi, [ebp + 8]
mov al, byte ptr ds:[BSS_PnpNodeNumber]
mov [esi], al
pop es
popa
mov esp, ebp
pop ebp
mov eax, [BSS_PnpResult]
ret
END
/* EOF */

View file

@ -1,96 +0,0 @@
/*
* FreeLoader
* Copyright (C) 2011 Hervé Poussineau
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.text
.code16
#include <arch/pc/x86common.h>
/*
* U16 PxeCallApi(U16 Segment, U16 Offset, U16 Service, VOID *Parameter);
*
* RETURNS:
*/
_pxe_function:
.word 0
_pxe_entry_point:
.long 0
_pxe_buffer_segment:
.word 0
_pxe_buffer_offset:
.word 0
_pxe_result:
.word 0
EXTERN(_PxeCallApi)
.code32
pushl %ebp
movl %esp,%ebp
pushal
push %es
/* copy entry point */
movl 0x08(%ebp),%eax
shll $16,%eax
movw 0x0C(%ebp),%ax
movl %eax,_pxe_entry_point
/* copy function */
movw 0x10(%ebp),%ax
movw %ax,_pxe_function
/* convert pointer to data buffer to segment/offset */
movl 0x14(%ebp),%eax
shrl $4,%eax
andl $0xf000,%eax
movw %ax,_pxe_buffer_segment
movl 0x14(%ebp),%eax
andl $0xffff,%eax
movw %ax,_pxe_buffer_offset
call switch_to_real
.code16
movw _pxe_buffer_segment,%ax
push %ax
movw _pxe_buffer_offset,%ax
push %ax
movw _pxe_function,%ax
push %ax
lcall *_pxe_entry_point
addw $6,%sp
movw %ax,_pxe_result
call switch_to_prot
.code32
pop %es
popal
movl %ebp,%esp
popl %ebp
movw _pxe_result,%ax
ret
/* EOF */

View file

@ -1,190 +0,0 @@
/*
* FreeLoader
* Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.text
.code16
#include <arch/pc/x86common.h>
#define I386FLAG_CF HEX(0001) // Carry Flag
#define I386FLAG_ZF HEX(0040) // Zero Flag
#define I386FLAG_SF HEX(0080) // Sign Flag
/* Only these flags are propagated into Int386() */
#define FLAGS_PROP (I386FLAG_CF | \
I386FLAG_ZF | \
I386FLAG_SF)
Int386_REGS:
Int386_eax:
.long 0
Int386_ebx:
.long 0
Int386_ecx:
.long 0
Int386_edx:
.long 0
Int386_esi:
.long 0
Int386_edi:
.long 0
Int386_ebp:
.long 0
Int386_ds:
.word 0
Int386_es:
.word 0
Int386_fs:
.word 0
Int386_gs:
.word 0
Int386_eflags:
.long 0
Int386_vector:
.long 0
Int386_regsin:
.long 0
Int386_regsout:
.long 0
/*
* int Int386(int ivec, REGS* in, REGS* out);
*/
EXTERN(_Int386)
.code32
/* Get the function parameters */
movl 0x04(%esp),%eax
movl %eax,Int386_vector
movb %al,Int386_vector_opcode
movl 0x08(%esp),%eax
movl %eax,Int386_regsin
movl 0x0c(%esp),%eax
movl %eax,Int386_regsout
/* Save all registers + segment registers */
pushw %ds
pushw %es
pushw %fs
pushw %gs
pushal
/* Copy the input regs to our variables */
movl $Int386_REGS,%edi
movl Int386_regsin,%esi
movl $0x28,%ecx
cld
rep
movsb
call switch_to_real
.code16
/* Setup the registers */
movw %cs:Int386_ds,%ax
movw %ax,%ds /* DS register */
movw %cs:Int386_es,%ax
movw %ax,%es /* ES register */
movw %cs:Int386_fs,%ax
movw %ax,%fs /* FS register */
movw %cs:Int386_gs,%ax
movw %ax,%gs /* GS register */
/* Prepare EFLAGS for recover */
pushf
movw %cs:Int386_eflags, %ax
popw %cx
andw $FLAGS_PROP, %ax
andw $~FLAGS_PROP, %cx
orw %cx, %ax
pushw %ax
/* Recover general purpose registers */
movl %cs:Int386_eax,%eax /* EAX register */
movl %cs:Int386_ebx,%ebx /* EBX register */
movl %cs:Int386_ecx,%ecx /* ECX register */
movl %cs:Int386_edx,%edx /* EDX register */
movl %cs:Int386_esi,%esi /* ESI register */
movl %cs:Int386_edi,%edi /* EDI register */
/* Recover previously prepared flags */
popf
/* Do not set the flags register */
/* only return its value in regsout */
//pushl Int386_eflags
//popfl /* EFLAGS register */
/* Call the interrupt vector */
/*int Int386_vector*/
Int386_int_opcode:
.byte 0xcd
Int386_vector_opcode:
.byte 0x00
/* Save the registers */
movl %eax,%cs:Int386_eax /* EAX register */
movl %ebx,%cs:Int386_ebx /* EBX register */
movl %ecx,%cs:Int386_ecx /* ECX register */
movl %edx,%cs:Int386_edx /* EDX register */
movl %esi,%cs:Int386_esi /* ESI register */
movl %edi,%cs:Int386_edi /* EDI register */
movw %ds,%ax /* DS register */
movw %ax,%cs:Int386_ds
movw %es,%ax /* ES register */
movw %ax,%cs:Int386_es
movw %fs,%ax /* FS register */
movw %ax,%cs:Int386_fs
movw %gs,%ax /* GS register */
movw %ax,%cs:Int386_gs
pushf
popw %cs:Int386_eflags /* EFLAGS register */
call switch_to_prot
.code32
/* Copy the variables to the output regs */
movl $Int386_REGS,%esi
movl Int386_regsout,%edi
movl $0x28,%ecx
cld
rep
movsb
/* Restore segment and all other registers */
popal
popw %gs
popw %fs
popw %es
popw %ds
/* Get return value */
movl Int386_eax,%eax
ret

View file

@ -17,37 +17,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.text
.code16
#include <asm.inc>
#include <arch/pc/x86common.h>
.code32
EXTERN(_BootNewLinuxKernel)
call switch_to_real
.code16
EXTERN i386CallRealMode:PROC
/* Set the boot drive */
movb (_FrldrBootDrive),%dl
.code32
/* Load segment registers */
cli
movw $0x9000,%bx
movw %bx,%ds
movw %bx,%es
movw %bx,%fs
movw %bx,%gs
movw %bx,%ss
movw $0x9000,%sp
ljmpl $0x9020,$0x0000
.code32
/*
* VOID BootOldLinuxKernel(ULONG KernelSize);
*/
EXTERN(_BootOldLinuxKernel)
PUBLIC _BootOldLinuxKernel
_BootOldLinuxKernel:
/* First we have to copy the kernel down from 0x100000 to 0x10000 */
/* The reason we can overwrite low memory is because this code */
@ -55,25 +36,20 @@ EXTERN(_BootOldLinuxKernel)
/* 32k of code before we start interfering with Linux kernel address space. */
/* Get KernelSize in ECX and move the kernel down */
movl 0x04(%esp),%ecx
movl $0x100000,%esi
movl $0x10000,%edi
mov ecx, [esp + 4]
mov esi, HEX(100000)
mov edi, HEX(10000)
rep movsb
call switch_to_real
.code16
/* Fall through */
/* Set the boot drive */
movb (_FrldrBootDrive),%dl
PUBLIC _BootNewLinuxKernel
_BootNewLinuxKernel:
/* Load segment registers */
cli
movw $0x9000,%bx
movw %bx,%ds
movw %bx,%es
movw %bx,%fs
movw %bx,%gs
movw %bx,%ss
movw $0x9000,%sp
mov bx, FNID_BootLinuxKernel
call i386CallRealMode
ljmpl $0x9020,$0x0000
/* We should never get here */
int 3
END

View file

@ -1,55 +0,0 @@
/*
* FreeLoader
* Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <asm.inc>
#include <arch/pc/x86common.h>
EXTERN i386CallRealMode:PROC
.code32
/*
* VOID BootOldLinuxKernel(ULONG KernelSize);
*/
PUBLIC _BootOldLinuxKernel
_BootOldLinuxKernel:
/* First we have to copy the kernel down from 0x100000 to 0x10000 */
/* The reason we can overwrite low memory is because this code */
/* executes between 0000:8000 and 0000:FFFF. That leaves space for */
/* 32k of code before we start interfering with Linux kernel address space. */
/* Get KernelSize in ECX and move the kernel down */
mov ecx, [esp + 4]
mov esi, HEX(100000)
mov edi, HEX(10000)
rep movsb
/* Fall through */
PUBLIC _BootNewLinuxKernel
_BootNewLinuxKernel:
mov bx, FNID_BootLinuxKernel
call i386CallRealMode
/* We should never get here */
int 3
END

View file

@ -1,8 +0,0 @@
#include <asm.inc>
.code32
END

View file

@ -1,22 +0,0 @@
/*
Interface definitions for bget.c, the memory management package.
*/
typedef long bufsize;
void bpool (void *buffer, bufsize len);
void *bget (bufsize size);
void *bgetz (bufsize size);
void *bgetr (void *buffer, bufsize newsize);
void brel (void *buf);
void bectl (int (*compact)(bufsize sizereq, int sequence),
void *(*acquire)(bufsize size),
void (*release)(void *buf), bufsize pool_incr);
void bstats (bufsize *curalloc, bufsize *totfree, bufsize *maxfree,
long *nget, long *nrel);
void bstatse (bufsize *pool_incr, long *npool, long *npget,
long *nprel, long *ndget, long *ndrel);
void bufdump (void *buf);
void bpoold (void *pool, int dumpalloc, int dumpfree);
int bpoolv (void *pool);

View file

@ -56,7 +56,6 @@
/* internal headers */
#include <arcemul.h>
#include <bget.h>
#include <bytesex.h>
#include <cache.h>
#include <cmdline.h>

View file

@ -1,6 +1,6 @@
/*
* FreeLoader
* Copyright (C) 2006-2008 Aleksey Bragin <aleksey@reactos.org>
* Copyright (C) 2011 Timo Kreuzer (timo.kreuzer@reactos.org)
*
* 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
@ -20,84 +20,494 @@
#include <freeldr.h>
#include <debug.h>
//#define MM_DBG 1 // needs #define BufStats 1 in bget.c
#define FREELDR_HEAP_VERIFIER
ULONG MmMaximumHeapAlloc;
DBG_DEFAULT_CHANNEL(HEAP);
DBG_DEFAULT_CHANNEL(MEMORY);
#define DEFAULT_HEAP_SIZE (1024 * 1024)
#define TEMP_HEAP_SIZE (1024 * 1024)
VOID MmInitializeHeap(PVOID PageLookupTable)
#define REDZONE_MARK 0xCCCCCCCCCCCCCCCCULL
#define REDZONE_ALLOCATION 24
#define REDZONE_LOW_OFFSET 16
#define REDZONE_SIZE(Block) ((ULONG64*)Block->Data)
#define REDZONE_LOW(Block) ((ULONG64*)Block->Data + 1)
#define REDZONE_HI(Block) ((ULONG64*)((PUCHAR)Block->Data + 16 + *REDZONE_SIZE(Block)))
PVOID FrLdrDefaultHeap;
PVOID FrLdrTempHeap;
typedef struct _BLOCK_DATA
{
ULONG PagesNeeded = 0;
ULONG HeapStart = 0;
ULONG_PTR Flink:32;
ULONG_PTR Blink:32;
} BLOCK_DATA, *PBLOCK_DATA;
// Find contigious memory block for HEAP:STACK
PagesNeeded = HEAP_PAGES + STACK_PAGES;
HeapStart = MmFindAvailablePages(PageLookupTable, TotalPagesInLookupTable, PagesNeeded, FALSE);
if (HeapStart == 0)
{
UiMessageBox("Critical error: Can't allocate heap!");
return;
}
// Initialize BGET
bpool((PVOID)(HeapStart << MM_PAGE_SHIFT), PagesNeeded << MM_PAGE_SHIFT);
// Mark those pages as used
MmMarkPagesInLookupTable(PageLookupTableAddress, HeapStart, PagesNeeded, LoaderOsloaderHeap);
TRACE("Heap initialized, base 0x%08x, pages %d\n", (HeapStart << MM_PAGE_SHIFT), PagesNeeded);
}
PVOID MmHeapAlloc(ULONG MemorySize)
typedef struct _HEAP_BLOCK
{
PVOID Result;
USHORT Size;
USHORT PreviousSize;
ULONG Tag;
BLOCK_DATA Data[];
} HEAP_BLOCK, *PHEAP_BLOCK;
if (MemorySize > MM_PAGE_SIZE)
{
WARN("Consider using other functions to allocate %d bytes of memory!\n", MemorySize);
}
// Get the buffer from BGET pool
Result = bget(MemorySize);
if (Result == NULL)
{
ERR("Heap allocation for %d bytes failed\n", MemorySize);
}
#ifdef MM_DBG
{
LONG CurAlloc, TotalFree, MaxFree, NumberOfGets, NumberOfRels;
// Gather some stats
bstats(&CurAlloc, &TotalFree, &MaxFree, &NumberOfGets, &NumberOfRels);
if (CurAlloc > MmMaximumHeapAlloc) MmMaximumHeapAlloc = CurAlloc;
TRACE("Current alloc %d, free %d, max alloc %lx, allocs %d, frees %d\n",
CurAlloc, TotalFree, MmMaximumHeapAlloc, NumberOfGets, NumberOfRels);
}
#endif
return Result;
}
VOID MmHeapFree(PVOID MemoryPointer)
typedef struct _HEAP
{
// Release the buffer to the pool
brel(MemoryPointer);
}
SIZE_T MaximumSize;
SIZE_T CurrentAllocBytes;
SIZE_T MaxAllocBytes;
ULONG NumAllocs;
ULONG NumFrees;
SIZE_T LargestAllocation;
ULONGLONG AllocationTime;
ULONGLONG FreeTime;
ULONG_PTR TerminatingBlock;
HEAP_BLOCK Blocks;
} HEAP, *PHEAP;
PVOID
NTAPI
ExAllocatePool(
IN POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes)
HeapCreate(
SIZE_T MaximumSize,
TYPE_OF_MEMORY MemoryType)
{
return MmHeapAlloc(NumberOfBytes);
PHEAP Heap;
PHEAP_BLOCK Block;
SIZE_T Remaining;
USHORT PreviousSize;
TRACE("HeapCreate(MemoryType=%ld)\n", MemoryType);
/* Allocate some memory for the heap */
MaximumSize = ALIGN_UP_BY(MaximumSize, MM_PAGE_SIZE);
Heap = MmAllocateMemoryWithType(MaximumSize, MemoryType);
if (!Heap)
{
ERR("HEAP: Failed to allocate heap of size 0x%lx, Type\n",
MaximumSize, MemoryType);
return NULL;
}
/* Initialize the heap header */
Heap->MaximumSize = MaximumSize;
Heap->CurrentAllocBytes = 0;
Heap->MaxAllocBytes = 0;
Heap->NumAllocs = 0;
Heap->NumFrees = 0;
Heap->LargestAllocation = 0;
/* Calculate what's left to process */
Remaining = (MaximumSize - sizeof(HEAP)) / sizeof(HEAP_BLOCK);
TRACE("Remaining = %ld\n", Remaining);
/* Substract 2 for the terminating entry (header + free entry) */
Remaining -= 2;
Block = &Heap->Blocks;
PreviousSize = 0;
/* Create free blocks */
while (Remaining > 1)
{
/* Initialize this free block */
Block->Size = (USHORT)min(MAXUSHORT, Remaining - 1);
Block->PreviousSize = PreviousSize;
Block->Tag = 0;
Block->Data[0].Flink = (Block - &Heap->Blocks) + Block->Size + 1;
Block->Data[0].Blink = (Block - &Heap->Blocks) - 1 - PreviousSize;
/* Substract current block size from remainder */
Remaining -= (Block->Size + 1);
/* Go to next block */
PreviousSize = Block->Size;
Block = Block + Block->Size + 1;
TRACE("Remaining = %ld\n", Remaining);
}
/* Now finish with a terminating block */
Heap->TerminatingBlock = Block - &Heap->Blocks;
Block->Size = 0;
Block->PreviousSize = PreviousSize;
Block->Tag = 'dnE#';
Block->Data[0].Flink = 0;
Block->Data[0].Blink = (Block - &Heap->Blocks) - 1 - PreviousSize;
Heap->Blocks.Data[0].Blink = Heap->TerminatingBlock;
return Heap;
}
VOID
HeapDestroy(
PVOID HeapHandle)
{
PHEAP Heap = HeapHandle;
/* Mark all pages as firmware temporary, so they are free for the kernel */
MmMarkPagesInLookupTable(PageLookupTableAddress,
(ULONG_PTR)Heap / MM_PAGE_SIZE,
(PFN_COUNT)(Heap->MaximumSize / MM_PAGE_SIZE),
LoaderFirmwareTemporary);
}
VOID
HeapRelease(
PVOID HeapHandle)
{
PHEAP Heap = HeapHandle;
PHEAP_BLOCK Block;
PUCHAR StartAddress, EndAddress;
PFN_COUNT FreePages, AllFreePages = 0;
TRACE("HeapRelease(%p)\n", HeapHandle);
/* Loop all heap chunks */
for (Block = &Heap->Blocks;
Block->Size != 0;
Block = Block + 1 + Block->Size)
{
/* Continue, if its not free */
if (Block->Tag != 0)
{
#ifdef FREELDR_HEAP_VERIFIER
/* Verify size and redzones */
ASSERT(*REDZONE_SIZE(Block) <= Block->Size * sizeof(HEAP_BLOCK));
ASSERT(*REDZONE_LOW(Block) == REDZONE_MARK);
ASSERT(*REDZONE_HI(Block) == REDZONE_MARK);
#endif
continue;
}
/* Calculate page aligned start address of the free region */
StartAddress = ALIGN_UP_POINTER_BY(Block->Data, PAGE_SIZE);
/* Walk over adjacent free blocks */
while (Block->Tag == 0) Block = Block + Block->Size + 1;
/* Check if this was the last block */
if (Block->Size == 0)
{
/* Align the end address up to cover the end of the heap */
EndAddress = ALIGN_UP_POINTER_BY(Block->Data, PAGE_SIZE);
}
else
{
/* Align the end address down to not cover any allocations */
EndAddress = ALIGN_DOWN_POINTER_BY(Block->Data, PAGE_SIZE);
}
/* Check if we have free pages */
if (EndAddress > StartAddress)
{
/* Calculate the size of the free region in pages */
FreePages = (PFN_COUNT)((EndAddress - StartAddress) / MM_PAGE_SIZE);
AllFreePages += FreePages;
/* Now mark the pages free */
MmMarkPagesInLookupTable(PageLookupTableAddress,
(ULONG_PTR)StartAddress / MM_PAGE_SIZE,
FreePages,
LoaderFree);
}
/* bail out, if it was the last block */
if (Block->Size == 0) break;
}
TRACE("HeapRelease() done, freed %ld pages\n", AllFreePages);
}
VOID
HeapCleanupAll(VOID)
{
PHEAP Heap;
Heap = FrLdrDefaultHeap;
TRACE("Heap statistics for default heap:\n"
"CurrentAlloc=0x%lx, MaxAlloc=0x%lx, LargestAllocation=0x%lx\n"
"NumAllocs=%ld, NumFrees=%ld\n",
Heap->CurrentAllocBytes, Heap->MaxAllocBytes, Heap->LargestAllocation,
Heap->NumAllocs, Heap->NumFrees);
TRACE("AllocTime = %I64d, FreeTime = %I64d, sum = %I64d\n",
Heap->AllocationTime, Heap->FreeTime, Heap->AllocationTime + Heap->FreeTime);
/* Release fre pages */
HeapRelease(FrLdrDefaultHeap);
Heap = FrLdrTempHeap;
TRACE("Heap statistics for temp heap:\n"
"CurrentAlloc=0x%lx, MaxAlloc=0x%lx, LargestAllocation=0x%lx\n"
"NumAllocs=%ld, NumFrees=%ld\n",
Heap->CurrentAllocBytes, Heap->MaxAllocBytes, Heap->LargestAllocation,
Heap->NumAllocs, Heap->NumFrees);
/* Destroy the heap */
HeapDestroy(FrLdrTempHeap);
}
static VOID
HeapRemoveFreeList(
PHEAP Heap,
PHEAP_BLOCK Block)
{
PHEAP_BLOCK Previous, Next;
Next = &Heap->Blocks + Block->Data[0].Flink;
Previous = &Heap->Blocks + Block->Data[0].Blink;
ASSERT((Next->Tag == 0) || (Next->Tag == 'dnE#'));
ASSERT(Next->Data[0].Blink == Block - &Heap->Blocks);
ASSERT((Previous->Tag == 0) || (Previous->Tag == 'dnE#'));
ASSERT(Previous->Data[0].Flink == Block - &Heap->Blocks);
Next->Data[0].Blink = Previous - &Heap->Blocks;
Previous->Data[0].Flink = Next - &Heap->Blocks;
}
static VOID
HeapInsertFreeList(
PHEAP Heap,
PHEAP_BLOCK FreeBlock)
{
PHEAP_BLOCK ListHead, NextBlock;
ASSERT(FreeBlock->Tag == 0);
/* Terminating block serves as free list head */
ListHead = &Heap->Blocks + Heap->TerminatingBlock;
for (NextBlock = &Heap->Blocks + ListHead->Data[0].Flink;
NextBlock < FreeBlock;
NextBlock = &Heap->Blocks + NextBlock->Data[0].Flink);
FreeBlock->Data[0].Flink = NextBlock - &Heap->Blocks;
FreeBlock->Data[0].Blink = NextBlock->Data[0].Blink;
NextBlock->Data[0].Blink = FreeBlock - &Heap->Blocks;
NextBlock = &Heap->Blocks + FreeBlock->Data[0].Blink;
NextBlock->Data[0].Flink = FreeBlock - &Heap->Blocks;
}
PVOID
HeapAllocate(
PVOID HeapHandle,
SIZE_T ByteSize,
ULONG Tag)
{
PHEAP Heap = HeapHandle;
PHEAP_BLOCK Block, NextBlock;
USHORT BlockSize, Remaining;
ULONGLONG Time = __rdtsc();
#ifdef FREELDR_HEAP_VERIFIER
/* Add space for a size field and 2 redzones */
ByteSize += REDZONE_ALLOCATION;
#endif
/* Check if the allocation is too large */
if ((ByteSize + sizeof(HEAP_BLOCK)) > MAXUSHORT * sizeof(HEAP_BLOCK))
{
ERR("HEAP: Allocation of 0x%lx bytes too large\n", ByteSize);
return NULL;
}
/* We need a proper tag */
if (Tag == 0) Tag = 'enoN';
/* Calculate alloc size */
BlockSize = (USHORT)((ByteSize + sizeof(HEAP_BLOCK) - 1) / sizeof(HEAP_BLOCK));
/* Walk the free block list */
Block = &Heap->Blocks + Heap->TerminatingBlock;
for (Block = &Heap->Blocks + Block->Data[0].Flink;
Block->Size != 0;
Block = &Heap->Blocks + Block->Data[0].Flink)
{
ASSERT(Block->Tag == 0);
/* Continue, if its too small */
if (Block->Size < BlockSize) continue;
/* This block is just fine, use it */
Block->Tag = Tag;
/* Remove this entry from the free list */
HeapRemoveFreeList(Heap, Block);
/* Calculate the remaining size */
Remaining = Block->Size - BlockSize;
/* Check if the remaining space is large enough for a new block */
if (Remaining > 1)
{
/* Make the allocated block as large as neccessary */
Block->Size = BlockSize;
/* Get pointer to the new block */
NextBlock = Block + 1 + BlockSize;
/* Make it a free block */
NextBlock->Tag = 0;
NextBlock->Size = Remaining - 1;
NextBlock->PreviousSize = BlockSize;
BlockSize = NextBlock->Size;
HeapInsertFreeList(Heap, NextBlock);
/* Advance to the next block */
NextBlock = NextBlock + 1 + BlockSize;
}
else
{
/* Not enough left, use the full block */
BlockSize = Block->Size;
/* Get the next block */
NextBlock = Block + 1 + BlockSize;
}
/* Update the next blocks back link */
NextBlock->PreviousSize = BlockSize;
/* Update heap usage */
Heap->NumAllocs++;
Heap->CurrentAllocBytes += Block->Size * sizeof(HEAP_BLOCK);
Heap->MaxAllocBytes = max(Heap->MaxAllocBytes, Heap->CurrentAllocBytes);
Heap->LargestAllocation = max(Heap->LargestAllocation,
Block->Size * sizeof(HEAP_BLOCK));
Heap->AllocationTime += (__rdtsc() - Time);
TRACE("HeapAllocate(%p, %ld, %.4s) -> return %p\n",
HeapHandle, ByteSize, &Tag, Block->Data);
/* HACK: zero out the allocation */
RtlZeroMemory(Block->Data, Block->Size * sizeof(HEAP_BLOCK));
#ifdef FREELDR_HEAP_VERIFIER
/* Write size and redzones */
*REDZONE_SIZE(Block) = ByteSize - REDZONE_ALLOCATION;
*REDZONE_LOW(Block) = REDZONE_MARK;
*REDZONE_HI(Block) = REDZONE_MARK;
/* Allcoation starts after size field and redzone */
return (PUCHAR)Block->Data + REDZONE_LOW_OFFSET;
#endif
/* Return pointer to the data */
return Block->Data;
}
/* We found nothing */
WARN("HEAP: nothing suitable found for 0x%lx bytes\n", ByteSize);
return NULL;
}
VOID
HeapFree(
PVOID HeapHandle,
PVOID Pointer,
ULONG Tag)
{
PHEAP Heap = HeapHandle;
PHEAP_BLOCK Block, PrevBlock, NextBlock;
ULONGLONG Time = __rdtsc();
TRACE("HeapFree(%p, %p)\n", HeapHandle, Pointer);
ASSERT(Tag != 'dnE#');
/* Check if the block is really inside this heap */
if ((Pointer < (PVOID)(Heap + 1)) ||
(Pointer > (PVOID)((PUCHAR)Heap + Heap->MaximumSize)))
{
ERR("HEAP: trying to free %p outside of heap %p\n", Pointer, Heap);
ASSERT(FALSE);
}
Block = ((PHEAP_BLOCK)Pointer) - 1;
#ifdef FREELDR_HEAP_VERIFIER
Block = (PHEAP_BLOCK)((PUCHAR)Block - REDZONE_LOW_OFFSET);
/* Verify size and redzones */
ASSERT(*REDZONE_SIZE(Block) <= Block->Size * sizeof(HEAP_BLOCK));
ASSERT(*REDZONE_LOW(Block) == REDZONE_MARK);
ASSERT(*REDZONE_HI(Block) == REDZONE_MARK);
#endif
/* Check if the tag matches */
if ((Tag && (Block->Tag != Tag)) || (Block->Tag == 0))
{
ERR("HEAP: Bad tag! Pointer=%p: block tag '%.4s', requested '%.4s', size=0x%lx\n",
Pointer, &Block->Tag, &Tag, Block->Size);
ASSERT(FALSE);
}
/* Mark as free */
Block->Tag = 0;
/* Update heap usage */
Heap->NumFrees++;
Heap->CurrentAllocBytes -= Block->Size * sizeof(HEAP_BLOCK);
/* Get pointers to the next and previous block */
PrevBlock = Block - Block->PreviousSize - 1;
NextBlock = Block + Block->Size + 1;
/* Check if next block is free */
if ((NextBlock->Tag == 0) &&
((Block->Size + NextBlock->Size + 1) <= MAXUSHORT))
{
/* Merge next block into current */
Block->Size += NextBlock->Size + 1;
HeapRemoveFreeList(Heap, NextBlock);
NextBlock = Block + Block->Size + 1;
}
/* Check if there is a block before and it's free */
if ((Block->PreviousSize != 0) && (PrevBlock->Tag == 0) &&
((PrevBlock->Size + Block->Size + 1) <= MAXUSHORT))
{
/* Merge current block into previous */
PrevBlock->Size += Block->Size + 1;
Block = PrevBlock;
}
else
{
/* Insert the entry into the free list */
HeapInsertFreeList(Heap, Block);
}
/* Update the next block's back link */
NextBlock->PreviousSize = Block->Size;
Heap->FreeTime += (__rdtsc() - Time);
}
/* Wrapper functions *********************************************************/
VOID
MmInitializeHeap(PVOID PageLookupTable)
{
TRACE("MmInitializeHeap()\n");
/* Create the default heap */
FrLdrDefaultHeap = HeapCreate(DEFAULT_HEAP_SIZE, LoaderOsloaderHeap);
ASSERT(FrLdrDefaultHeap);
/* Create a temporary heap */
FrLdrTempHeap = HeapCreate(TEMP_HEAP_SIZE, LoaderFirmwareTemporary);
ASSERT(FrLdrTempHeap);
TRACE("MmInitializeHeap() done, default heap %p, temp heap %p\n",
FrLdrDefaultHeap, FrLdrTempHeap);
}
PVOID
MmHeapAlloc(SIZE_T MemorySize)
{
return HeapAllocate(FrLdrDefaultHeap, MemorySize, 'pHmM');
}
VOID
MmHeapFree(PVOID MemoryPointer)
{
HeapFree(FrLdrDefaultHeap, MemoryPointer, 'pHmM');
}
#undef ExAllocatePoolWithTag
PVOID
NTAPI
ExAllocatePoolWithTag(
@ -105,26 +515,33 @@ ExAllocatePoolWithTag(
IN SIZE_T NumberOfBytes,
IN ULONG Tag)
{
return MmHeapAlloc(NumberOfBytes);
return HeapAllocate(FrLdrDefaultHeap, NumberOfBytes, Tag);
}
PVOID
NTAPI
ExAllocatePool(
IN POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes)
{
return HeapAllocate(FrLdrDefaultHeap, NumberOfBytes, 0);
}
#undef ExFreePool
VOID
NTAPI
ExFreePool(
IN PVOID P)
{
MmHeapFree(P);
HeapFree(FrLdrDefaultHeap, P, 0);
}
#undef ExFreePoolWithTag
VOID
NTAPI
ExFreePoolWithTag(
IN PVOID P,
IN ULONG Tag)
{
ExFreePool(P);
HeapFree(FrLdrDefaultHeap, P, Tag);
}
PVOID
@ -136,7 +553,7 @@ RtlAllocateHeap(
{
PVOID ptr;
ptr = MmHeapAlloc(Size);
ptr = HeapAllocate(FrLdrDefaultHeap, Size, ' ltR');
if (ptr && (Flags & HEAP_ZERO_MEMORY))
{
RtlZeroMemory(ptr, Size);
@ -152,6 +569,7 @@ RtlFreeHeap(
IN ULONG Flags,
IN PVOID HeapBase)
{
MmHeapFree(HeapBase);
HeapFree(FrLdrDefaultHeap, HeapBase, ' ltR');
return TRUE;
}

View file

@ -1,575 +0,0 @@
/*
* FreeLoader
* Copyright (C) 2011 Timo Kreuzer (timo.kreuzer@reactos.org)
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <freeldr.h>
#include <debug.h>
#define FREELDR_HEAP_VERIFIER
DBG_DEFAULT_CHANNEL(HEAP);
#define DEFAULT_HEAP_SIZE (1024 * 1024)
#define TEMP_HEAP_SIZE (1024 * 1024)
#define REDZONE_MARK 0xCCCCCCCCCCCCCCCCULL
#define REDZONE_ALLOCATION 24
#define REDZONE_LOW_OFFSET 16
#define REDZONE_SIZE(Block) ((ULONG64*)Block->Data)
#define REDZONE_LOW(Block) ((ULONG64*)Block->Data + 1)
#define REDZONE_HI(Block) ((ULONG64*)((PUCHAR)Block->Data + 16 + *REDZONE_SIZE(Block)))
PVOID FrLdrDefaultHeap;
PVOID FrLdrTempHeap;
typedef struct _BLOCK_DATA
{
ULONG_PTR Flink:32;
ULONG_PTR Blink:32;
} BLOCK_DATA, *PBLOCK_DATA;
typedef struct _HEAP_BLOCK
{
USHORT Size;
USHORT PreviousSize;
ULONG Tag;
BLOCK_DATA Data[];
} HEAP_BLOCK, *PHEAP_BLOCK;
typedef struct _HEAP
{
SIZE_T MaximumSize;
SIZE_T CurrentAllocBytes;
SIZE_T MaxAllocBytes;
ULONG NumAllocs;
ULONG NumFrees;
SIZE_T LargestAllocation;
ULONGLONG AllocationTime;
ULONGLONG FreeTime;
ULONG_PTR TerminatingBlock;
HEAP_BLOCK Blocks;
} HEAP, *PHEAP;
PVOID
HeapCreate(
SIZE_T MaximumSize,
TYPE_OF_MEMORY MemoryType)
{
PHEAP Heap;
PHEAP_BLOCK Block;
SIZE_T Remaining;
USHORT PreviousSize;
TRACE("HeapCreate(MemoryType=%ld)\n", MemoryType);
/* Allocate some memory for the heap */
MaximumSize = ALIGN_UP_BY(MaximumSize, MM_PAGE_SIZE);
Heap = MmAllocateMemoryWithType(MaximumSize, MemoryType);
if (!Heap)
{
ERR("HEAP: Failed to allocate heap of size 0x%lx, Type\n",
MaximumSize, MemoryType);
return NULL;
}
/* Initialize the heap header */
Heap->MaximumSize = MaximumSize;
Heap->CurrentAllocBytes = 0;
Heap->MaxAllocBytes = 0;
Heap->NumAllocs = 0;
Heap->NumFrees = 0;
Heap->LargestAllocation = 0;
/* Calculate what's left to process */
Remaining = (MaximumSize - sizeof(HEAP)) / sizeof(HEAP_BLOCK);
TRACE("Remaining = %ld\n", Remaining);
/* Substract 2 for the terminating entry (header + free entry) */
Remaining -= 2;
Block = &Heap->Blocks;
PreviousSize = 0;
/* Create free blocks */
while (Remaining > 1)
{
/* Initialize this free block */
Block->Size = (USHORT)min(MAXUSHORT, Remaining - 1);
Block->PreviousSize = PreviousSize;
Block->Tag = 0;
Block->Data[0].Flink = (Block - &Heap->Blocks) + Block->Size + 1;
Block->Data[0].Blink = (Block - &Heap->Blocks) - 1 - PreviousSize;
/* Substract current block size from remainder */
Remaining -= (Block->Size + 1);
/* Go to next block */
PreviousSize = Block->Size;
Block = Block + Block->Size + 1;
TRACE("Remaining = %ld\n", Remaining);
}
/* Now finish with a terminating block */
Heap->TerminatingBlock = Block - &Heap->Blocks;
Block->Size = 0;
Block->PreviousSize = PreviousSize;
Block->Tag = 'dnE#';
Block->Data[0].Flink = 0;
Block->Data[0].Blink = (Block - &Heap->Blocks) - 1 - PreviousSize;
Heap->Blocks.Data[0].Blink = Heap->TerminatingBlock;
return Heap;
}
VOID
HeapDestroy(
PVOID HeapHandle)
{
PHEAP Heap = HeapHandle;
/* Mark all pages as firmware temporary, so they are free for the kernel */
MmMarkPagesInLookupTable(PageLookupTableAddress,
(ULONG_PTR)Heap / MM_PAGE_SIZE,
(PFN_COUNT)(Heap->MaximumSize / MM_PAGE_SIZE),
LoaderFirmwareTemporary);
}
VOID
HeapRelease(
PVOID HeapHandle)
{
PHEAP Heap = HeapHandle;
PHEAP_BLOCK Block;
PUCHAR StartAddress, EndAddress;
PFN_COUNT FreePages, AllFreePages = 0;
TRACE("HeapRelease(%p)\n", HeapHandle);
/* Loop all heap chunks */
for (Block = &Heap->Blocks;
Block->Size != 0;
Block = Block + 1 + Block->Size)
{
/* Continue, if its not free */
if (Block->Tag != 0)
{
#ifdef FREELDR_HEAP_VERIFIER
/* Verify size and redzones */
ASSERT(*REDZONE_SIZE(Block) <= Block->Size * sizeof(HEAP_BLOCK));
ASSERT(*REDZONE_LOW(Block) == REDZONE_MARK);
ASSERT(*REDZONE_HI(Block) == REDZONE_MARK);
#endif
continue;
}
/* Calculate page aligned start address of the free region */
StartAddress = ALIGN_UP_POINTER_BY(Block->Data, PAGE_SIZE);
/* Walk over adjacent free blocks */
while (Block->Tag == 0) Block = Block + Block->Size + 1;
/* Check if this was the last block */
if (Block->Size == 0)
{
/* Align the end address up to cover the end of the heap */
EndAddress = ALIGN_UP_POINTER_BY(Block->Data, PAGE_SIZE);
}
else
{
/* Align the end address down to not cover any allocations */
EndAddress = ALIGN_DOWN_POINTER_BY(Block->Data, PAGE_SIZE);
}
/* Check if we have free pages */
if (EndAddress > StartAddress)
{
/* Calculate the size of the free region in pages */
FreePages = (PFN_COUNT)((EndAddress - StartAddress) / MM_PAGE_SIZE);
AllFreePages += FreePages;
/* Now mark the pages free */
MmMarkPagesInLookupTable(PageLookupTableAddress,
(ULONG_PTR)StartAddress / MM_PAGE_SIZE,
FreePages,
LoaderFree);
}
/* bail out, if it was the last block */
if (Block->Size == 0) break;
}
TRACE("HeapRelease() done, freed %ld pages\n", AllFreePages);
}
VOID
HeapCleanupAll(VOID)
{
PHEAP Heap;
Heap = FrLdrDefaultHeap;
TRACE("Heap statistics for default heap:\n"
"CurrentAlloc=0x%lx, MaxAlloc=0x%lx, LargestAllocation=0x%lx\n"
"NumAllocs=%ld, NumFrees=%ld\n",
Heap->CurrentAllocBytes, Heap->MaxAllocBytes, Heap->LargestAllocation,
Heap->NumAllocs, Heap->NumFrees);
TRACE("AllocTime = %I64d, FreeTime = %I64d, sum = %I64d\n",
Heap->AllocationTime, Heap->FreeTime, Heap->AllocationTime + Heap->FreeTime);
/* Release fre pages */
HeapRelease(FrLdrDefaultHeap);
Heap = FrLdrTempHeap;
TRACE("Heap statistics for temp heap:\n"
"CurrentAlloc=0x%lx, MaxAlloc=0x%lx, LargestAllocation=0x%lx\n"
"NumAllocs=%ld, NumFrees=%ld\n",
Heap->CurrentAllocBytes, Heap->MaxAllocBytes, Heap->LargestAllocation,
Heap->NumAllocs, Heap->NumFrees);
/* Destroy the heap */
HeapDestroy(FrLdrTempHeap);
}
static VOID
HeapRemoveFreeList(
PHEAP Heap,
PHEAP_BLOCK Block)
{
PHEAP_BLOCK Previous, Next;
Next = &Heap->Blocks + Block->Data[0].Flink;
Previous = &Heap->Blocks + Block->Data[0].Blink;
ASSERT((Next->Tag == 0) || (Next->Tag == 'dnE#'));
ASSERT(Next->Data[0].Blink == Block - &Heap->Blocks);
ASSERT((Previous->Tag == 0) || (Previous->Tag == 'dnE#'));
ASSERT(Previous->Data[0].Flink == Block - &Heap->Blocks);
Next->Data[0].Blink = Previous - &Heap->Blocks;
Previous->Data[0].Flink = Next - &Heap->Blocks;
}
static VOID
HeapInsertFreeList(
PHEAP Heap,
PHEAP_BLOCK FreeBlock)
{
PHEAP_BLOCK ListHead, NextBlock;
ASSERT(FreeBlock->Tag == 0);
/* Terminating block serves as free list head */
ListHead = &Heap->Blocks + Heap->TerminatingBlock;
for (NextBlock = &Heap->Blocks + ListHead->Data[0].Flink;
NextBlock < FreeBlock;
NextBlock = &Heap->Blocks + NextBlock->Data[0].Flink);
FreeBlock->Data[0].Flink = NextBlock - &Heap->Blocks;
FreeBlock->Data[0].Blink = NextBlock->Data[0].Blink;
NextBlock->Data[0].Blink = FreeBlock - &Heap->Blocks;
NextBlock = &Heap->Blocks + FreeBlock->Data[0].Blink;
NextBlock->Data[0].Flink = FreeBlock - &Heap->Blocks;
}
PVOID
HeapAllocate(
PVOID HeapHandle,
SIZE_T ByteSize,
ULONG Tag)
{
PHEAP Heap = HeapHandle;
PHEAP_BLOCK Block, NextBlock;
USHORT BlockSize, Remaining;
ULONGLONG Time = __rdtsc();
#ifdef FREELDR_HEAP_VERIFIER
/* Add space for a size field and 2 redzones */
ByteSize += REDZONE_ALLOCATION;
#endif
/* Check if the allocation is too large */
if ((ByteSize + sizeof(HEAP_BLOCK)) > MAXUSHORT * sizeof(HEAP_BLOCK))
{
ERR("HEAP: Allocation of 0x%lx bytes too large\n", ByteSize);
return NULL;
}
/* We need a proper tag */
if (Tag == 0) Tag = 'enoN';
/* Calculate alloc size */
BlockSize = (USHORT)((ByteSize + sizeof(HEAP_BLOCK) - 1) / sizeof(HEAP_BLOCK));
/* Walk the free block list */
Block = &Heap->Blocks + Heap->TerminatingBlock;
for (Block = &Heap->Blocks + Block->Data[0].Flink;
Block->Size != 0;
Block = &Heap->Blocks + Block->Data[0].Flink)
{
ASSERT(Block->Tag == 0);
/* Continue, if its too small */
if (Block->Size < BlockSize) continue;
/* This block is just fine, use it */
Block->Tag = Tag;
/* Remove this entry from the free list */
HeapRemoveFreeList(Heap, Block);
/* Calculate the remaining size */
Remaining = Block->Size - BlockSize;
/* Check if the remaining space is large enough for a new block */
if (Remaining > 1)
{
/* Make the allocated block as large as neccessary */
Block->Size = BlockSize;
/* Get pointer to the new block */
NextBlock = Block + 1 + BlockSize;
/* Make it a free block */
NextBlock->Tag = 0;
NextBlock->Size = Remaining - 1;
NextBlock->PreviousSize = BlockSize;
BlockSize = NextBlock->Size;
HeapInsertFreeList(Heap, NextBlock);
/* Advance to the next block */
NextBlock = NextBlock + 1 + BlockSize;
}
else
{
/* Not enough left, use the full block */
BlockSize = Block->Size;
/* Get the next block */
NextBlock = Block + 1 + BlockSize;
}
/* Update the next blocks back link */
NextBlock->PreviousSize = BlockSize;
/* Update heap usage */
Heap->NumAllocs++;
Heap->CurrentAllocBytes += Block->Size * sizeof(HEAP_BLOCK);
Heap->MaxAllocBytes = max(Heap->MaxAllocBytes, Heap->CurrentAllocBytes);
Heap->LargestAllocation = max(Heap->LargestAllocation,
Block->Size * sizeof(HEAP_BLOCK));
Heap->AllocationTime += (__rdtsc() - Time);
TRACE("HeapAllocate(%p, %ld, %.4s) -> return %p\n",
HeapHandle, ByteSize, &Tag, Block->Data);
/* HACK: zero out the allocation */
RtlZeroMemory(Block->Data, Block->Size * sizeof(HEAP_BLOCK));
#ifdef FREELDR_HEAP_VERIFIER
/* Write size and redzones */
*REDZONE_SIZE(Block) = ByteSize - REDZONE_ALLOCATION;
*REDZONE_LOW(Block) = REDZONE_MARK;
*REDZONE_HI(Block) = REDZONE_MARK;
/* Allcoation starts after size field and redzone */
return (PUCHAR)Block->Data + REDZONE_LOW_OFFSET;
#endif
/* Return pointer to the data */
return Block->Data;
}
/* We found nothing */
WARN("HEAP: nothing suitable found for 0x%lx bytes\n", ByteSize);
return NULL;
}
VOID
HeapFree(
PVOID HeapHandle,
PVOID Pointer,
ULONG Tag)
{
PHEAP Heap = HeapHandle;
PHEAP_BLOCK Block, PrevBlock, NextBlock;
ULONGLONG Time = __rdtsc();
TRACE("HeapFree(%p, %p)\n", HeapHandle, Pointer);
ASSERT(Tag != 'dnE#');
/* Check if the block is really inside this heap */
if ((Pointer < (PVOID)(Heap + 1)) ||
(Pointer > (PVOID)((PUCHAR)Heap + Heap->MaximumSize)))
{
ERR("HEAP: trying to free %p outside of heap %p\n", Pointer, Heap);
ASSERT(FALSE);
}
Block = ((PHEAP_BLOCK)Pointer) - 1;
#ifdef FREELDR_HEAP_VERIFIER
Block = (PHEAP_BLOCK)((PUCHAR)Block - REDZONE_LOW_OFFSET);
/* Verify size and redzones */
ASSERT(*REDZONE_SIZE(Block) <= Block->Size * sizeof(HEAP_BLOCK));
ASSERT(*REDZONE_LOW(Block) == REDZONE_MARK);
ASSERT(*REDZONE_HI(Block) == REDZONE_MARK);
#endif
/* Check if the tag matches */
if ((Tag && (Block->Tag != Tag)) || (Block->Tag == 0))
{
ERR("HEAP: Bad tag! Pointer=%p: block tag '%.4s', requested '%.4s', size=0x%lx\n",
Pointer, &Block->Tag, &Tag, Block->Size);
ASSERT(FALSE);
}
/* Mark as free */
Block->Tag = 0;
/* Update heap usage */
Heap->NumFrees++;
Heap->CurrentAllocBytes -= Block->Size * sizeof(HEAP_BLOCK);
/* Get pointers to the next and previous block */
PrevBlock = Block - Block->PreviousSize - 1;
NextBlock = Block + Block->Size + 1;
/* Check if next block is free */
if ((NextBlock->Tag == 0) &&
((Block->Size + NextBlock->Size + 1) <= MAXUSHORT))
{
/* Merge next block into current */
Block->Size += NextBlock->Size + 1;
HeapRemoveFreeList(Heap, NextBlock);
NextBlock = Block + Block->Size + 1;
}
/* Check if there is a block before and it's free */
if ((Block->PreviousSize != 0) && (PrevBlock->Tag == 0) &&
((PrevBlock->Size + Block->Size + 1) <= MAXUSHORT))
{
/* Merge current block into previous */
PrevBlock->Size += Block->Size + 1;
Block = PrevBlock;
}
else
{
/* Insert the entry into the free list */
HeapInsertFreeList(Heap, Block);
}
/* Update the next block's back link */
NextBlock->PreviousSize = Block->Size;
Heap->FreeTime += (__rdtsc() - Time);
}
/* Wrapper functions *********************************************************/
VOID
MmInitializeHeap(PVOID PageLookupTable)
{
TRACE("MmInitializeHeap()\n");
/* Create the default heap */
FrLdrDefaultHeap = HeapCreate(DEFAULT_HEAP_SIZE, LoaderOsloaderHeap);
ASSERT(FrLdrDefaultHeap);
/* Create a temporary heap */
FrLdrTempHeap = HeapCreate(TEMP_HEAP_SIZE, LoaderFirmwareTemporary);
ASSERT(FrLdrTempHeap);
TRACE("MmInitializeHeap() done, default heap %p, temp heap %p\n",
FrLdrDefaultHeap, FrLdrTempHeap);
}
PVOID
MmHeapAlloc(SIZE_T MemorySize)
{
return HeapAllocate(FrLdrDefaultHeap, MemorySize, 'pHmM');
}
VOID
MmHeapFree(PVOID MemoryPointer)
{
HeapFree(FrLdrDefaultHeap, MemoryPointer, 'pHmM');
}
PVOID
NTAPI
ExAllocatePoolWithTag(
IN POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes,
IN ULONG Tag)
{
return HeapAllocate(FrLdrDefaultHeap, NumberOfBytes, Tag);
}
PVOID
NTAPI
ExAllocatePool(
IN POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes)
{
return HeapAllocate(FrLdrDefaultHeap, NumberOfBytes, 0);
}
VOID
NTAPI
ExFreePool(
IN PVOID P)
{
HeapFree(FrLdrDefaultHeap, P, 0);
}
VOID
NTAPI
ExFreePoolWithTag(
IN PVOID P,
IN ULONG Tag)
{
HeapFree(FrLdrDefaultHeap, P, Tag);
}
PVOID
NTAPI
RtlAllocateHeap(
IN PVOID HeapHandle,
IN ULONG Flags,
IN SIZE_T Size)
{
PVOID ptr;
ptr = HeapAllocate(FrLdrDefaultHeap, Size, ' ltR');
if (ptr && (Flags & HEAP_ZERO_MEMORY))
{
RtlZeroMemory(ptr, Size);
}
return ptr;
}
BOOLEAN
NTAPI
RtlFreeHeap(
IN PVOID HeapHandle,
IN ULONG Flags,
IN PVOID HeapBase)
{
HeapFree(FrLdrDefaultHeap, HeapBase, ' ltR');
return TRUE;
}

File diff suppressed because it is too large Load diff

View file

@ -1,70 +0,0 @@
.file "longjmp.S"
/*
* Copyright (C) 1998, 1999, Jonathan S. Shapiro.
*
* This file is part of the EROS Operating System.
*
* 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; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* typedef struct {
* unsigned long ebx, esi, edi;
* unsigned long ebp;
* unsigned long sp;
* unsigned long pc;
* } jmp_buf[1];
*/
/*
* On entry, the stack to longjmp looks like:
*
* value
* ptr to jmp_buf
* return PC
*/
.globl _longjmp
_longjmp:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%ecx /* address of jmp_buf to ecx */
movl 12(%ebp),%eax /* return value to %eax */
testl %eax,%eax
jne 1f
incl %eax /* return 1 if handed 0 */
1:
movl (%ecx),%ebx /* restore %ebx */
movl 4(%ecx),%esi /* restore %esi */
movl 8(%ecx),%edi /* restore %edi */
/*
* From this instant on we are not running in a valid frame
*/
movl 12(%ecx),%ebp /* restore %ebp */
movl 16(%ecx),%esp /* restore %esp */
/* movl 20(%ecx),%eax return PC */
/*
* Since we are abandoning the stack in any case,
* there isn't much point in doing the usual return
* discipline.
*/
jmpl *20(%ecx)

View file

@ -1,61 +0,0 @@
.file "setjmp.S"
/*
* Copyright (C) 1998, 1999, Jonathan S. Shapiro.
*
* This file is part of the EROS Operating System.
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* #include <eros/i486/asm.h> */
/*
* typedef struct {
* unsigned long ebx, esi, edi;
* unsigned long ebp;
* unsigned long sp;
* unsigned long pc;
* } jmp_buf[1];
*/
/*
* On entry, the stack to setjmp looks like:
*
* ptr to jmp_buf
* return PC
*/
.globl _setjmp
.globl __setjmp
_setjmp:
__setjmp:
pushl %ebp
movl %esp,%ebp
movl 0x8(%ebp),%eax /* address of jmp_buf to eax */
movl %ebx,(%eax) /* save %ebx */
movl %esi,4(%eax) /* save %esi */
movl %edi,8(%eax) /* save %edi */
leal 8(%ebp),%edx /* calling proc's esp, not ours! */
movl %edx,16(%eax)
movl 4(%ebp), %edx /* save return PC */
movl %edx,20(%eax)
movl 0(%ebp),%edx /* calling proc's ebp, not ours! */
movl %edx,12(%eax)
xorl %eax,%eax /* return 0 the first time */
leave
ret

View file

@ -1,48 +0,0 @@
#include <stdio.h>
FILE *in;
FILE *out;
int main(int argc, char *argv[])
{
unsigned char ch;
int cnt = 0;
if (argc < 4)
{
printf("usage: bin2c infile.bin outfile.h array_name\n");
return -1;
}
if ((in = fopen(argv[1], "rb")) == NULL)
{
printf("Couldn't open data file.\n");
return -1;
}
if ((out = fopen(argv[2], "wb")) == NULL)
{
printf("Couldn't open output file.\n");
return -1;
}
fprintf(out, "unsigned char %s[] = {\n", argv[3]);
ch = fgetc(in);
while (!feof(in))
{
if (cnt != 0)
fprintf(out, ", ");
if (!(cnt % 16))
fprintf(out, "\n");
fprintf(out, "0x%02x", (int)ch);
cnt++;
ch = fgetc(in);
}
fprintf(out, "\n};\n");
fclose(in);
fclose(out);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,40 +0,0 @@
/*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <string>
#include <stdarg.h>
#ifdef __CYGWIN__
namespace std {
typedef basic_string<wchar_t> wstring;
}
#endif
std::string ssprintf ( const char* fmt, ... );
std::string ssvprintf ( const char* fmt, va_list args );
std::wstring sswprintf ( const wchar_t* fmt, ... );
std::wstring sswvprintf ( const wchar_t* fmt, va_list args );
#ifdef _UNICODE
#define sstprintf sswprintf
#define sstvprintf sswvprintf
#else
#define sstprintf ssprintf
#define sstvprintf ssvprintf
#endif

View file

@ -1,966 +0,0 @@
/*
* Copyright (C) 2005 Casper S. Hornstrup
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#ifdef WIN32
#include <direct.h>
#include <io.h>
#else
#include <sys/stat.h>
#include <unistd.h>
// Some hosts don't define PATH_MAX in unistd.h
#if !defined(PATH_MAX)
#include <limits.h>
#endif
#define MAX_PATH PATH_MAX
#endif
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "xml.h"
#include "ssprintf.h"
#ifndef MAX_PATH
#define MAX_PATH _MAX_PATH
#endif
using std::string;
using std::vector;
#ifdef WIN32
#define getcwd _getcwd
#endif//WIN32
static const char* WS = " \t\r\n";
static const char* WSEQ = " =\t\r\n";
string working_directory;
std::vector<char> vectorize(const std::string &str)
{
std::vector<char> result( str.size() + 1 );
strcpy( &result[0], str.c_str() );
return result;
}
void vectappend(std::vector<char> &strvec, const char *str)
{
if (*str) { strvec[strlen(&strvec[0])] = *str; str++; }
while (*str)
{
strvec.push_back(*str);
str++;
}
strvec.push_back(0);
}
void vectappend(std::vector<char> &strvec, const std::string &str)
{
vectappend(strvec, str.c_str());
}
void vectappend(std::vector<char> &strvec, char ch)
{
strvec[strlen(&strvec[0])] = ch;
strvec.push_back(0);
}
XMLException::XMLException (
const std::string& location,
const char* format, ... )
{
va_list args;
va_start ( args, format );
SetExceptionV ( location, format, args );
va_end ( args );
}
void XMLException::SetExceptionV ( const std::string& location, const char* format, va_list args )
{
_e = location + ": " + ssvprintf(format,args);
}
void XMLException::SetException ( const std::string& location, const char* format, ... )
{
va_list args;
va_start ( args, format );
SetExceptionV ( location, format, args );
va_end ( args );
}
XMLIncludes::~XMLIncludes()
{
for ( size_t i = 0; i < this->size(); i++ )
delete (*this)[i];
}
void
InitWorkingDirectory()
{
// store the current directory for path calculations
working_directory.resize ( MAX_PATH );
working_directory[0] = 0;
getcwd ( &working_directory[0], working_directory.size() );
working_directory.resize ( strlen ( working_directory.c_str() ) );
}
#ifdef _MSC_VER
unsigned __int64
#else
unsigned long long
#endif
filelen ( FILE* f )
{
#ifdef WIN32
return _filelengthi64 ( _fileno(f) );
#else
# if defined(__FreeBSD__) || defined(__APPLE__) || defined(__CYGWIN__)
struct stat file_stat;
if ( fstat(fileno(f), &file_stat) != 0 )
# else
struct stat64 file_stat;
if ( fstat64(fileno(f), &file_stat) != 0 )
# endif // __FreeBSD__
return 0;
return file_stat.st_size;
#endif // WIN32
}
Path::Path()
{
if ( !working_directory.size() )
InitWorkingDirectory();
string s ( working_directory );
const char* p = strtok ( &s[0], "/\\" );
while ( p )
{
if ( *p )
path.push_back ( p );
p = strtok ( NULL, "/\\" );
}
}
Path::Path ( const Path& cwd, const string& file )
{
string s ( cwd.Fixup ( file, false ) );
const char* p = strtok ( &s[0], "/\\" );
while ( p )
{
if ( *p )
path.push_back ( p );
p = strtok ( NULL, "/\\" );
}
}
string
Path::Fixup ( const string& file, bool include_filename ) const
{
if ( strchr ( "/\\", file[0] )
#ifdef WIN32
// this squirreliness is b/c win32 has drive letters and *nix doesn't...
|| file[1] == ':'
#endif//WIN32
)
{
return file;
}
vector<string> pathtmp ( path );
vector<char> tmp = vectorize( file );
const char* prev = strtok ( &tmp[0], "/\\" );
const char* p = strtok ( NULL, "/\\" );
while ( p )
{
if ( !strcmp ( prev, "." ) )
; // do nothing
else if ( !strcmp ( prev, ".." ) )
{
// this squirreliness is b/c win32 has drive letters and *nix doesn't...
#ifdef WIN32
if ( pathtmp.size() > 1 )
#else
if ( pathtmp.size() )
#endif
pathtmp.resize ( pathtmp.size() - 1 );
}
else
pathtmp.push_back ( prev );
prev = p;
p = strtok ( NULL, "/\\" );
}
if ( include_filename )
pathtmp.push_back ( prev );
// reuse tmp variable to return recombined path
tmp = vectorize("");
for ( size_t i = 0; i < pathtmp.size(); i++ )
{
// this squirreliness is b/c win32 has drive letters and *nix doesn't...
#ifdef WIN32
if ( i ) vectappend(tmp, "/");
#else
vectappend(tmp, "/");
#endif
vectappend(tmp, pathtmp[i]);
}
return &tmp[0];
}
string
Path::RelativeFromWorkingDirectory ()
{
string out = "";
for ( size_t i = 0; i < path.size(); i++ )
{
out += "/" + path[i];
}
return RelativeFromWorkingDirectory ( out );
}
string
Path::RelativeFromWorkingDirectory ( const string& path )
{
return Path::RelativeFromDirectory ( path, working_directory );
}
string
Path::RelativeFromDirectory (
const string& path,
const string& base_directory )
{
vector<string> vbase, vpath, vout;
Path::Split ( vbase, base_directory, true );
Path::Split ( vpath, path, true );
#ifdef WIN32
// this squirreliness is b/c win32 has drive letters and *nix doesn't...
// not possible to do relative across different drive letters
{
char path_driveletter = (path[1] == ':') ? toupper(path[0]) : 0;
char base_driveletter = (base_directory[1] == ':') ? toupper(base_directory[0]) : 0;
if ( path_driveletter != base_driveletter )
return path;
}
#endif
size_t i = 0;
while ( i < vbase.size() && i < vpath.size() && vbase[i] == vpath[i] )
++i;
// did we go through all of the path?
if ( vbase.size() == vpath.size() && i == vpath.size() )
return ".";
if ( i < vbase.size() )
{
// path goes above our base directory, we will need some ..'s
for ( size_t j = i; j < vbase.size(); j++ )
vout.push_back ( ".." );
}
while ( i < vpath.size() )
vout.push_back ( vpath[i++] );
// now merge vout into a string again
string out = vout[0];
for ( i = 1; i < vout.size(); i++ )
{
out += "/" + vout[i];
}
return out;
}
void
Path::Split (
vector<string>& out,
const string& path,
bool include_last )
{
string s ( path );
const char* prev = strtok ( &s[0], "/\\" );
const char* p = strtok ( NULL, "/\\" );
out.resize ( 0 );
while ( p )
{
if ( strcmp ( prev, "." ) )
out.push_back ( prev );
prev = p;
p = strtok ( NULL, "/\\" );
}
if ( include_last && strcmp ( prev, "." ) )
out.push_back ( prev );
// special-case where path only has "."
// don't move this check up higher as it might miss
// some funny paths...
if ( !out.size() && !strcmp ( prev, "." ) )
out.push_back ( "." );
}
XMLFile::XMLFile()
{
}
void
XMLFile::close()
{
_buf.resize(0);
_p = _end = NULL;
}
bool
XMLFile::open ( const string& filename_ )
{
close();
FILE* f = fopen ( filename_.c_str(), "rb" );
if ( !f )
return false;
unsigned long len = (unsigned long)filelen(f);
_buf.resize ( len );
fread ( &_buf[0], 1, len, f );
fclose ( f );
_p = _buf.c_str();
_end = _p + len;
_filename = filename_;
next_token();
return true;
}
// next_token() moves the pointer to next token, which may be
// an xml element or a text element, basically it's a glorified
// skipspace, normally the user of this class won't need to call
// this function
void
XMLFile::next_token()
{
_p += strspn ( _p, WS );
}
bool
XMLFile::next_is_text()
{
return *_p != '<';
}
bool
XMLFile::more_tokens ()
{
return _p != _end;
}
// get_token() is used to return a token, and move the pointer
// past the token
bool
XMLFile::get_token ( string& token )
{
const char* tokend;
if ( !strncmp ( _p, "<!--", 4 ) )
{
tokend = strstr ( _p, "-->" );
if ( !tokend )
tokend = _end;
else
tokend += 3;
}
else if ( !strncmp ( _p, "<?", 2 ) )
{
tokend = strstr ( _p, "?>" );
if ( !tokend )
tokend = _end;
else
tokend += 2;
}
else if ( *_p == '<' )
{
tokend = strchr ( _p, '>' );
if ( !tokend )
tokend = _end;
else
++tokend;
}
else
{
tokend = strchr ( _p, '<' );
if ( !tokend )
tokend = _end;
while ( tokend > _p && isspace(tokend[-1]) )
--tokend;
}
if ( tokend == _p )
return false;
token = string ( _p, tokend-_p );
_p = tokend;
next_token();
return true;
}
bool
XMLFile::get_token ( string& token, string& location )
{
location = Location();
return get_token ( token );
}
string
XMLFile::Location() const
{
int line = 1;
const char* p = strchr ( _buf.c_str(), '\n' );
while ( p && p < _p )
{
++line;
p = strchr ( p+1, '\n' );
}
return ssprintf ( "%s(%i)",_filename.c_str(), line );
}
XMLAttribute::XMLAttribute()
{
}
XMLAttribute::XMLAttribute(
const string& name_,
const string& value_ )
: name(name_), value(value_)
{
}
XMLAttribute::XMLAttribute ( const XMLAttribute& src )
: name(src.name), value(src.value)
{
}
XMLAttribute& XMLAttribute::operator = ( const XMLAttribute& src )
{
name = src.name;
value = src.value;
return *this;
}
XMLElement::XMLElement (
XMLFile* xmlFile,
const string& location )
: xmlFile ( xmlFile ),
location ( location ),
parentElement ( NULL )
{
}
XMLElement::~XMLElement()
{
size_t i;
for ( i = 0; i < attributes.size(); i++ )
delete attributes[i];
for ( i = 0; i < subElements.size(); i++ )
delete subElements[i];
}
void
XMLElement::AddSubElement ( XMLElement* e )
{
subElements.push_back ( e );
e->parentElement = this;
}
// Parse()
// This function takes a single xml tag ( i.e. beginning with '<' and
// ending with '>', and parses out it's tag name and constituent
// attributes.
// Return Value: returns true if you need to look for a </tag> for
// the one it just parsed...
bool
XMLElement::Parse (
const string& token,
bool& end_tag )
{
const char* p = token.c_str();
assert ( *p == '<' );
++p;
p += strspn ( p, WS );
// check if this is a comment
if ( !strncmp ( p, "!--", 3 ) )
{
name = "!--";
end_tag = false;
return false; // never look for end tag to a comment
}
end_tag = ( *p == '/' );
if ( end_tag )
{
++p;
p += strspn ( p, WS );
}
const char* end = strpbrk ( p, WS );
if ( !end )
{
end = strpbrk ( p, "/>" );
assert ( end );
}
name = string ( p, end-p );
p = end;
p += strspn ( p, WS );
while ( *p != '>' && *p != '/' )
{
end = strpbrk ( p, WSEQ );
if ( !end )
{
end = strpbrk ( p, "/>" );
assert ( end );
}
string attribute ( p, end-p ), value;
p = end;
p += strspn ( p, WS );
if ( *p == '=' )
{
++p;
p += strspn ( p, WS );
char quote = 0;
if ( strchr ( "\"'", *p ) )
{
quote = *p++;
end = strchr ( p, quote );
}
else
{
end = strpbrk ( p, WS );
}
if ( !end )
{
end = strchr ( p, '>' );
assert(end);
if ( end[-1] == '/' )
end--;
}
value = string ( p, end-p );
p = end;
if ( quote && *p == quote )
p++;
p += strspn ( p, WS );
}
else if ( name[0] != '!' )
{
throw XMLSyntaxErrorException (
location,
"attributes must have values" );
}
attributes.push_back ( new XMLAttribute ( attribute, value ) );
}
return !( *p == '/' ) && !end_tag;
}
XMLAttribute*
XMLElement::GetAttribute (
const string& attribute,
bool required )
{
// this would be faster with a tree-based container, but our attribute
// lists are likely to stay so short as to not be an issue.
for ( size_t i = 0; i < attributes.size(); i++ )
{
if ( attribute == attributes[i]->name )
return attributes[i];
}
if ( required )
{
throw XMLRequiredAttributeNotFoundException (
location,
attribute,
name );
}
return NULL;
}
const XMLAttribute*
XMLElement::GetAttribute (
const string& attribute,
bool required ) const
{
// this would be faster with a tree-based container, but our attribute
// lists are likely to stay so short as to not be an issue.
for ( size_t i = 0; i < attributes.size(); i++ )
{
if ( attribute == attributes[i]->name )
return attributes[i];
}
if ( required )
{
throw XMLRequiredAttributeNotFoundException (
location,
attribute,
name );
}
return NULL;
}
int
XMLElement::FindElement ( const std::string& type, int prev ) const
{
int done = subElements.size();
while ( ++prev < done )
{
XMLElement* e = subElements[prev];
if ( e->name == type )
return prev;
}
return -1;
}
int
XMLElement::GetElements (
const std::string& type,
std::vector<XMLElement*>& v )
{
int find = FindElement ( type );
v.resize ( 0 );
while ( find != -1 )
{
v.push_back ( subElements[find] );
find = FindElement ( type, find );
}
return v.size();
}
int
XMLElement::GetElements (
const std::string& type,
std::vector<const XMLElement*>& v ) const
{
int find = FindElement ( type );
v.resize ( 0 );
while ( find != -1 )
{
v.push_back ( subElements[find] );
find = FindElement ( type, find );
}
return v.size();
}
// XMLParse()
// This function reads a "token" from the file loaded in XMLFile
// if it finds a tag that is non-singular, it parses sub-elements and/or
// inner text into the XMLElement that it is building to return.
// Return Value: an XMLElement allocated via the new operator that contains
// it's parsed data. Keep calling this function until it returns NULL
// (no more data)
XMLElement*
XMLParse (
XMLFile& f,
XMLIncludes* includes,
const Path& path,
bool* pend_tag = NULL )
{
string token, location;
if ( !f.get_token(token,location) )
return NULL;
bool end_tag, is_include = false;
while
(
token[0] != '<'
|| !strncmp ( token.c_str (), "<!--", 4 )
|| !strncmp ( token.c_str (), "<?", 2 )
)
{
if ( token[0] != '<' )
{
throw XMLSyntaxErrorException (
location,
"expecting xml tag, not '%s'",
token.c_str () );
}
if ( !f.get_token ( token, location ) )
return NULL;
}
XMLElement* e = new XMLElement (
&f,
location );
bool bNeedEnd = e->Parse ( token, end_tag );
if ( e->name == "xi:include" && includes )
{
XMLAttribute* att;
att = e->GetAttribute ( "href", true );
assert ( att );
string includeFile ( path.Fixup ( att->value, true ) );
string topIncludeFile (
Path::RelativeFromWorkingDirectory ( includeFile ) );
includes->push_back (
new XMLInclude ( e, path, topIncludeFile ) );
is_include = true;
}
if ( !bNeedEnd )
{
if ( pend_tag )
*pend_tag = end_tag;
else if ( end_tag )
{
delete e;
throw XMLSyntaxErrorException (
location,
"end tag '%s' not expected",
token.c_str() );
return NULL;
}
return e;
}
bool bThisMixingErrorReported = false;
while ( f.more_tokens () )
{
if ( f.next_is_text () )
{
if ( !f.get_token ( token, location ) || token.size () == 0 )
{
throw XMLInvalidBuildFileException (
location,
"internal tool error - get_token() failed when more_tokens() returned true" );
break;
}
if ( e->subElements.size() && !bThisMixingErrorReported )
{
throw XMLSyntaxErrorException (
location,
"mixing of inner text with sub elements" );
bThisMixingErrorReported = true;
}
if ( strchr ( token.c_str (), '>' ) )
{
throw XMLSyntaxErrorException (
location,
"invalid symbol '>'" );
}
if ( e->value.size() > 0 )
{
throw XMLSyntaxErrorException (
location,
"multiple instances of inner text" );
e->value += " " + token;
}
else
e->value = token;
}
else
{
XMLElement* e2 = XMLParse (
f, is_include ? NULL : includes, path, &end_tag );
if ( !e2 )
{
string e_location = e->location;
string e_name = e->name;
delete e;
throw XMLInvalidBuildFileException (
e_location,
"end of file found looking for end tag: </%s>",
e_name.c_str() );
break;
}
if ( end_tag )
{
if ( e->name != e2->name )
{
string e2_location = e2->location;
string e_name = e->name;
string e2_name = e2->name;
delete e;
delete e2;
throw XMLSyntaxErrorException (
e2_location,
"end tag name mismatch - found </%s> but was expecting </%s>",
e2_name.c_str(),
e_name.c_str() );
break;
}
delete e2;
break;
}
if ( e->value.size () > 0 && !bThisMixingErrorReported )
{
string e_location = e->location;
delete e;
throw XMLSyntaxErrorException (
e_location,
"mixing of inner text with sub elements" );
bThisMixingErrorReported = true;
}
e->AddSubElement ( e2 );
}
}
return e;
}
void
XMLReadFile (
XMLFile& f,
XMLElement& head,
XMLIncludes& includes,
const Path& path )
{
for ( ;; )
{
XMLElement* e = XMLParse ( f, &includes, path );
if ( !e )
return;
head.AddSubElement ( e );
}
}
XMLElement*
XMLLoadInclude (
XMLInclude& include,
XMLIncludes& includes )
{
XMLAttribute* att;
att = include.e->GetAttribute("href", true);
assert(att);
string file ( include.path.Fixup(att->value, true) );
string top_file ( Path::RelativeFromWorkingDirectory ( file ) );
include.e->attributes.push_back ( new XMLAttribute ( "top_href", top_file ) );
XMLFile* fInc = new XMLFile();
if ( !fInc->open ( file ) )
{
include.fileExists = false;
// look for xi:fallback element
for ( size_t i = 0; i < include.e->subElements.size (); i++ )
{
XMLElement* e2 = include.e->subElements[i];
if ( e2->name == "xi:fallback" )
{
// now look for xi:include below...
for ( i = 0; i < e2->subElements.size (); i++ )
{
XMLElement* e3 = e2->subElements[i];
if ( e3->name == "xi:include" )
{
att = e3->GetAttribute ( "href", true );
assert ( att );
string includeFile (
include.path.Fixup ( att->value, true ) );
string topIncludeFile (
Path::RelativeFromWorkingDirectory ( includeFile ) );
XMLInclude* fallbackInclude =
new XMLInclude ( e3, include.path, topIncludeFile );
XMLElement* value = XMLLoadInclude (*fallbackInclude, includes );
delete fallbackInclude;
return value;
}
}
throw XMLInvalidBuildFileException (
e2->location,
"<xi:fallback> must have a <xi:include> sub-element" );
return NULL;
}
}
return NULL;
}
else
{
include.fileExists = true;
XMLElement* new_e = new XMLElement (
fInc,
include.e->location );
new_e->name = "xi:included";
Path path2 ( include.path, att->value );
XMLReadFile ( *fInc, *new_e, includes, path2 );
return new_e;
}
}
XMLElement*
XMLLoadFile (
const string& filename,
const Path& path,
XMLIncludes& includes )
{
XMLFile* f = new XMLFile();
if ( !f->open ( filename ) )
{
delete f;
throw XMLFileNotFoundException ( "(virtual)", filename );
return NULL;
}
XMLElement* head = new XMLElement ( f, "(virtual)" );
XMLReadFile ( *f, *head, includes, path );
for ( size_t i = 0; i < includes.size (); i++ )
{
XMLElement* e = includes[i]->e;
XMLElement* e2 = XMLLoadInclude ( *includes[i], includes );
if ( !e2 )
{
throw XMLFileNotFoundException (
f->Location(),
e->GetAttribute ( "top_href", true )->value );
}
XMLElement* parent = e->parentElement;
XMLElement** parent_container = NULL;
if ( !parent )
{
string location = e->location;
delete e;
delete f;
throw XMLException ( location, "internal tool error: xi:include doesn't have a parent" );
return NULL;
}
for ( size_t j = 0; j < parent->subElements.size (); j++ )
{
if ( parent->subElements[j] == e )
{
parent_container = &parent->subElements[j];
break;
}
}
if ( !parent_container )
{
string location = e->location;
delete e;
delete f;
throw XMLException ( location, "internal tool error: couldn't find xi:include in parent's sub-elements" );
return NULL;
}
// replace inclusion tree with the imported tree
e2->parentElement = e->parentElement;
e2->name = e->name;
e2->attributes = e->attributes;
*parent_container = e2;
e->attributes.resize ( 0 );
delete e;
}
delete f;
return head;
}
XMLElement*
XMLLoadFile ( const string& filename )
{
Path path;
XMLIncludes includes;
return XMLLoadFile ( filename, path, includes );
}

View file

@ -1,242 +0,0 @@
/*
* Copyright (C) 2005 Casper S. Hornstrup
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <string>
#include <vector>
#include <stdarg.h>
class XMLElement;
extern std::string working_directory;
void
InitWorkingDirectory();
#ifdef _MSC_VER
unsigned __int64
#else
unsigned long long
#endif
filelen ( FILE* f );
class XMLException
{
public:
XMLException ( const std::string& location, const char* format, ... );
const std::string& operator *() { return _e; }
protected:
XMLException() {}
void SetExceptionV ( const std::string& location, const char* format, va_list args );
void SetException ( const std::string& location, const char* format, ... );
private:
std::string _e;
};
class XMLSyntaxErrorException : public XMLException
{
public:
XMLSyntaxErrorException (
const std::string& location,
const char* format, ... )
{
va_list args;
va_start ( args, format );
SetExceptionV ( location, format, args );
va_end ( args );
}
};
class XMLRequiredAttributeNotFoundException : public XMLException
{
public:
XMLRequiredAttributeNotFoundException (
const std::string& location,
const std::string& attributeName,
const std::string& elementName )
{
SetException ( location, "Required attribute '%s' not found in element '%s'",
attributeName.c_str(),
elementName.c_str() );
}
};
class XMLInvalidBuildFileException : public XMLException
{
public:
XMLInvalidBuildFileException (
const std::string& location,
const char* format,
... )
{
va_list args;
va_start ( args, format );
SetExceptionV ( location, format, args );
va_end ( args );
}
};
class XMLFileNotFoundException : public XMLException
{
public:
XMLFileNotFoundException (
const std::string& location,
const std::string& filename )
{
SetException ( location, "Can't open file '%s'", filename.c_str() );
}
};
class Path
{
std::vector<std::string> path;
public:
Path(); // initializes path to getcwd();
Path ( const Path& cwd, const std::string& filename );
std::string Fixup ( const std::string& filename, bool include_filename ) const;
std::string RelativeFromWorkingDirectory ();
static std::string RelativeFromWorkingDirectory ( const std::string& path );
static std::string RelativeFromDirectory ( const std::string& path, const std::string& base_directory);
static void Split (
std::vector<std::string>& out,
const std::string& path,
bool include_last );
};
class XMLInclude
{
public:
XMLElement *e;
Path path;
std::string topIncludeFilename;
bool fileExists;
XMLInclude (
XMLElement* e_,
const Path& path_,
const std::string topIncludeFilename_ )
: e ( e_ ),
path ( path_ ),
topIncludeFilename ( topIncludeFilename_ )
{
}
};
class XMLIncludes : public std::vector<XMLInclude*>
{
public:
~XMLIncludes();
};
class XMLFile
{
friend class XMLElement;
public:
XMLFile();
void close();
bool open(const std::string& filename);
void next_token();
bool next_is_text();
bool more_tokens();
bool get_token ( std::string& token );
bool get_token ( std::string& token, std::string& location );
const std::string& filename() { return _filename; }
std::string Location() const;
private:
std::string _buf, _filename;
const char *_p, *_end;
};
class XMLAttribute
{
public:
std::string name;
std::string value;
XMLAttribute();
XMLAttribute ( const std::string& name_, const std::string& value_ );
XMLAttribute ( const XMLAttribute& );
XMLAttribute& operator = ( const XMLAttribute& );
};
class XMLElement
{
public:
XMLFile* xmlFile;
std::string location;
std::string name;
std::vector<XMLAttribute*> attributes;
XMLElement* parentElement;
std::vector<XMLElement*> subElements;
std::string value;
XMLElement (
XMLFile* xmlFile,
const std::string& location );
~XMLElement();
bool Parse (
const std::string& token,
bool& end_tag);
void AddSubElement ( XMLElement* e );
XMLAttribute* GetAttribute (
const std::string& attribute,
bool required);
const XMLAttribute* GetAttribute (
const std::string& attribute,
bool required ) const;
int FindElement (
const std::string& type,
int prev = -1 ) const;
int GetElements (
const std::string& type,
std::vector<XMLElement*>& v );
int GetElements (
const std::string& type,
std::vector<const XMLElement*>& v ) const;
};
XMLElement*
XMLLoadFile (
const std::string& filename,
const Path& path,
XMLIncludes& includes );
XMLElement*
XMLLoadFile ( const std::string& filename );
std::vector<char> vectorize(const std::string &str);
void vectappend(std::vector<char> &strvec, char ch);
void vectappend(std::vector<char> &strvec, const char *charstr);
void vectappend(std::vector<char> &strvec, const std::string &str);