mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 18:42:56 +00:00
[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:
parent
aeac841aa8
commit
1550726927
33 changed files with 540 additions and 7742 deletions
|
@ -54,7 +54,7 @@ list(APPEND FREELDR_COMMON_SOURCE
|
||||||
inifile/parse.c
|
inifile/parse.c
|
||||||
mm/meminit.c
|
mm/meminit.c
|
||||||
mm/mm.c
|
mm/mm.c
|
||||||
mm/heap_new.c
|
mm/heap.c
|
||||||
reactos/registry.c
|
reactos/registry.c
|
||||||
reactos/arcname.c
|
reactos/arcname.c
|
||||||
reactos/archwsup.c
|
reactos/archwsup.c
|
||||||
|
@ -90,11 +90,11 @@ if(ARCH MATCHES i386)
|
||||||
arch/i386/i386bug.c
|
arch/i386/i386bug.c
|
||||||
arch/i386/i386disk.c
|
arch/i386/i386disk.c
|
||||||
arch/i386/i386idt.c
|
arch/i386/i386idt.c
|
||||||
arch/i386/i386pnp.cmake.S
|
arch/i386/i386pnp.S
|
||||||
arch/i386/i386rtl.c
|
arch/i386/i386rtl.c
|
||||||
arch/i386/i386trap.S
|
arch/i386/i386trap.S
|
||||||
arch/i386/i386vid.c
|
arch/i386/i386vid.c
|
||||||
arch/i386/linux.cmake.S
|
arch/i386/linux.S
|
||||||
arch/i386/machpc.c
|
arch/i386/machpc.c
|
||||||
arch/i386/mb.S
|
arch/i386/mb.S
|
||||||
arch/i386/miscboot.c
|
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})
|
add_library(freeldr_pe_dbg SHARED EXCLUDE_FROM_ALL ${FREELDR_BASE_SOURCE})
|
||||||
|
|
||||||
if(NOT MSVC)
|
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 "-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.lnk")
|
add_target_link_flags(freeldr_pe_dbg "-Wl,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
|
||||||
else()
|
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 "/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")
|
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})
|
add_library(setupldr_pe_dbg SHARED EXCLUDE_FROM_ALL ${FREELDR_BASE_SOURCE} ${SETUPLDR_SOURCE})
|
||||||
|
|
||||||
if(NOT MSVC)
|
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 "-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.lnk")
|
add_target_link_flags(setupldr_pe_dbg "-Wl,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
|
||||||
else()
|
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 "/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")
|
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")
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 */
|
|
|
@ -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 */
|
|
|
@ -20,19 +20,15 @@
|
||||||
#include <asm.inc>
|
#include <asm.inc>
|
||||||
#include <arch/pc/x86common.h>
|
#include <arch/pc/x86common.h>
|
||||||
|
|
||||||
.code32
|
EXTERN i386CallRealMode:PROC
|
||||||
|
|
||||||
|
.code32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* U32 PnpBiosSupported(VOID);
|
* U32 PnpBiosSupported(VOID);
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
*/
|
*/
|
||||||
_pnp_bios_entry_point:
|
|
||||||
.long 0
|
|
||||||
_pnp_bios_data_segment:
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
PUBLIC _PnpBiosSupported
|
PUBLIC _PnpBiosSupported
|
||||||
_PnpBiosSupported:
|
_PnpBiosSupported:
|
||||||
|
|
||||||
|
@ -79,14 +75,14 @@ pnp_loop:
|
||||||
|
|
||||||
/* Calculate the bios entry point (far pointer) */
|
/* Calculate the bios entry point (far pointer) */
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
mov ax, [esi + 15]
|
mov ax, [esi + HEX(0F)]
|
||||||
shl eax, 16
|
shl eax, 16
|
||||||
mov ax, [esi + 0x0D]
|
mov ax, [esi + HEX(0D)]
|
||||||
mov _pnp_bios_entry_point, eax
|
mov dword ptr ds:[BSS_PnpBiosEntryPoint], eax
|
||||||
|
|
||||||
/* Store bios data segment */
|
/* Store bios data segment */
|
||||||
mov ax, [esi + 0x1B]
|
mov ax, [esi + HEX(1B)]
|
||||||
mov _pnp_bios_data_segment, ax
|
mov word ptr ds:[BSS_PnpBiosDataSegment], ax
|
||||||
|
|
||||||
pnp_not_found:
|
pnp_not_found:
|
||||||
mov eax, edi
|
mov eax, edi
|
||||||
|
@ -104,13 +100,6 @@ pnp_not_found:
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
*/
|
*/
|
||||||
_pnp_result:
|
|
||||||
.long 0
|
|
||||||
_pnp_node_size:
|
|
||||||
.word 0
|
|
||||||
_pnp_node_count:
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
PUBLIC _PnpBiosGetDeviceNodeCount
|
PUBLIC _PnpBiosGetDeviceNodeCount
|
||||||
_PnpBiosGetDeviceNodeCount:
|
_PnpBiosGetDeviceNodeCount:
|
||||||
|
|
||||||
|
@ -120,41 +109,18 @@ _PnpBiosGetDeviceNodeCount:
|
||||||
pusha
|
pusha
|
||||||
push es
|
push es
|
||||||
|
|
||||||
call switch_to_real
|
mov bx, FNID_PnpBiosGetDeviceNodeCount
|
||||||
.code16
|
call i386CallRealMode
|
||||||
|
|
||||||
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 esi, [ebp + 8]
|
mov esi, [ebp + 8]
|
||||||
mov ax, _pnp_node_size
|
mov ax, [BSS_PnpNodeSize]
|
||||||
movzx ecx, ax
|
movzx ecx, ax
|
||||||
mov [esi], ecx
|
mov [esi], ecx
|
||||||
|
|
||||||
mov esi, [ebp + 12]
|
mov esi, [ebp + 12]
|
||||||
mov ax, _pnp_node_count
|
mov ax, [BSS_PnpNodeCount]
|
||||||
movzx ecx, ax
|
movzx ecx, ax
|
||||||
mov [esi], eax
|
mov [esi], ecx
|
||||||
|
|
||||||
pop es
|
pop es
|
||||||
popa
|
popa
|
||||||
|
@ -162,7 +128,7 @@ _PnpBiosGetDeviceNodeCount:
|
||||||
mov esp, ebp
|
mov esp, ebp
|
||||||
pop ebp
|
pop ebp
|
||||||
|
|
||||||
mov eax, _pnp_result
|
mov eax, dword ptr [BSS_PnpResult]
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -172,16 +138,8 @@ _PnpBiosGetDeviceNodeCount:
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
*/
|
*/
|
||||||
_pnp_buffer_segment:
|
PUBLIC _PnpBiosGetDeviceNode
|
||||||
.word 0
|
_PnpBiosGetDeviceNode:
|
||||||
_pnp_buffer_offset:
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
_pnp_node_number:
|
|
||||||
.byte 0
|
|
||||||
|
|
||||||
EXTERN(_PnpBiosGetDeviceNode)
|
|
||||||
.code32
|
|
||||||
|
|
||||||
push ebp
|
push ebp
|
||||||
mov ebp, esp
|
mov ebp, esp
|
||||||
|
@ -192,54 +150,23 @@ EXTERN(_PnpBiosGetDeviceNode)
|
||||||
/* get current node number */
|
/* get current node number */
|
||||||
mov esi, [ebp + 8]
|
mov esi, [ebp + 8]
|
||||||
mov al, [esi]
|
mov al, [esi]
|
||||||
mov _pnp_node_number, al
|
mov byte ptr ds:[BSS_PnpNodeNumber], al
|
||||||
|
|
||||||
/* convert pointer to node buffer to segment/offset */
|
/* convert pointer to node buffer to segment/offset */
|
||||||
mov eax, [ebp + 12]
|
mov eax, [ebp + 12]
|
||||||
shr eax, 4
|
shr eax, 4
|
||||||
and eax, 0xf000
|
and eax, HEX(0f000)
|
||||||
mov _pnp_buffer_segment, ax
|
mov word ptr ds:[BSS_PnpBiosBufferSegment], ax
|
||||||
mov eax, [ebp + 12]
|
mov eax, [ebp + 12]
|
||||||
and eax, 0xffff
|
and eax, HEX(0ffff)
|
||||||
mov _pnp_buffer_offset, ax
|
mov word ptr ds:[BSS_PnpBiosBufferOffset], ax
|
||||||
|
|
||||||
call switch_to_real
|
mov bx, FNID_PnpBiosGetDeviceNode
|
||||||
.code16
|
call i386CallRealMode
|
||||||
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
/* update node number */
|
/* update node number */
|
||||||
mov esi, [ebp + 8]
|
mov esi, [ebp + 8]
|
||||||
mov al, _pnp_node_number
|
mov al, byte ptr ds:[BSS_PnpNodeNumber]
|
||||||
mov [esi], al
|
mov [esi], al
|
||||||
|
|
||||||
pop es
|
pop es
|
||||||
|
@ -248,8 +175,9 @@ EXTERN(_PnpBiosGetDeviceNode)
|
||||||
mov esp, ebp
|
mov esp, ebp
|
||||||
pop ebp
|
pop ebp
|
||||||
|
|
||||||
mov eax, _pnp_result
|
mov eax, [BSS_PnpResult]
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
END
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -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 */
|
|
|
@ -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 */
|
|
||||||
|
|
|
@ -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
|
|
|
@ -17,37 +17,18 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.text
|
#include <asm.inc>
|
||||||
.code16
|
|
||||||
|
|
||||||
#include <arch/pc/x86common.h>
|
#include <arch/pc/x86common.h>
|
||||||
|
|
||||||
.code32
|
EXTERN i386CallRealMode:PROC
|
||||||
EXTERN(_BootNewLinuxKernel)
|
|
||||||
call switch_to_real
|
|
||||||
.code16
|
|
||||||
|
|
||||||
/* Set the boot drive */
|
.code32
|
||||||
movb (_FrldrBootDrive),%dl
|
|
||||||
|
|
||||||
/* 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);
|
* VOID BootOldLinuxKernel(ULONG KernelSize);
|
||||||
*/
|
*/
|
||||||
EXTERN(_BootOldLinuxKernel)
|
PUBLIC _BootOldLinuxKernel
|
||||||
|
_BootOldLinuxKernel:
|
||||||
|
|
||||||
/* First we have to copy the kernel down from 0x100000 to 0x10000 */
|
/* First we have to copy the kernel down from 0x100000 to 0x10000 */
|
||||||
/* The reason we can overwrite low memory is because this code */
|
/* 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. */
|
/* 32k of code before we start interfering with Linux kernel address space. */
|
||||||
|
|
||||||
/* Get KernelSize in ECX and move the kernel down */
|
/* Get KernelSize in ECX and move the kernel down */
|
||||||
movl 0x04(%esp),%ecx
|
mov ecx, [esp + 4]
|
||||||
movl $0x100000,%esi
|
mov esi, HEX(100000)
|
||||||
movl $0x10000,%edi
|
mov edi, HEX(10000)
|
||||||
rep movsb
|
rep movsb
|
||||||
|
|
||||||
call switch_to_real
|
/* Fall through */
|
||||||
.code16
|
|
||||||
|
|
||||||
/* Set the boot drive */
|
PUBLIC _BootNewLinuxKernel
|
||||||
movb (_FrldrBootDrive),%dl
|
_BootNewLinuxKernel:
|
||||||
|
|
||||||
/* Load segment registers */
|
mov bx, FNID_BootLinuxKernel
|
||||||
cli
|
call i386CallRealMode
|
||||||
movw $0x9000,%bx
|
|
||||||
movw %bx,%ds
|
|
||||||
movw %bx,%es
|
|
||||||
movw %bx,%fs
|
|
||||||
movw %bx,%gs
|
|
||||||
movw %bx,%ss
|
|
||||||
movw $0x9000,%sp
|
|
||||||
|
|
||||||
ljmpl $0x9020,$0x0000
|
/* We should never get here */
|
||||||
|
int 3
|
||||||
|
|
||||||
|
END
|
||||||
|
|
|
@ -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
|
|
|
@ -1,8 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
#include <asm.inc>
|
|
||||||
|
|
||||||
.code32
|
|
||||||
|
|
||||||
|
|
||||||
END
|
|
|
@ -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);
|
|
|
@ -56,7 +56,6 @@
|
||||||
|
|
||||||
/* internal headers */
|
/* internal headers */
|
||||||
#include <arcemul.h>
|
#include <arcemul.h>
|
||||||
#include <bget.h>
|
|
||||||
#include <bytesex.h>
|
#include <bytesex.h>
|
||||||
#include <cache.h>
|
#include <cache.h>
|
||||||
#include <cmdline.h>
|
#include <cmdline.h>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* FreeLoader
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,84 +20,494 @@
|
||||||
#include <freeldr.h>
|
#include <freeldr.h>
|
||||||
#include <debug.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_PTR Flink:32;
|
||||||
ULONG HeapStart = 0;
|
ULONG_PTR Blink:32;
|
||||||
|
} BLOCK_DATA, *PBLOCK_DATA;
|
||||||
|
|
||||||
// Find contigious memory block for HEAP:STACK
|
typedef struct _HEAP_BLOCK
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
PVOID Result;
|
USHORT Size;
|
||||||
|
USHORT PreviousSize;
|
||||||
|
ULONG Tag;
|
||||||
|
BLOCK_DATA Data[];
|
||||||
|
} HEAP_BLOCK, *PHEAP_BLOCK;
|
||||||
|
|
||||||
if (MemorySize > MM_PAGE_SIZE)
|
typedef struct _HEAP
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
// Release the buffer to the pool
|
SIZE_T MaximumSize;
|
||||||
brel(MemoryPointer);
|
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
|
PVOID
|
||||||
NTAPI
|
HeapCreate(
|
||||||
ExAllocatePool(
|
SIZE_T MaximumSize,
|
||||||
IN POOL_TYPE PoolType,
|
TYPE_OF_MEMORY MemoryType)
|
||||||
IN SIZE_T NumberOfBytes)
|
|
||||||
{
|
{
|
||||||
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
|
PVOID
|
||||||
NTAPI
|
NTAPI
|
||||||
ExAllocatePoolWithTag(
|
ExAllocatePoolWithTag(
|
||||||
|
@ -105,26 +515,33 @@ ExAllocatePoolWithTag(
|
||||||
IN SIZE_T NumberOfBytes,
|
IN SIZE_T NumberOfBytes,
|
||||||
IN ULONG Tag)
|
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
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
ExFreePool(
|
ExFreePool(
|
||||||
IN PVOID P)
|
IN PVOID P)
|
||||||
{
|
{
|
||||||
MmHeapFree(P);
|
HeapFree(FrLdrDefaultHeap, P, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ExFreePoolWithTag
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
ExFreePoolWithTag(
|
ExFreePoolWithTag(
|
||||||
IN PVOID P,
|
IN PVOID P,
|
||||||
IN ULONG Tag)
|
IN ULONG Tag)
|
||||||
{
|
{
|
||||||
ExFreePool(P);
|
HeapFree(FrLdrDefaultHeap, P, Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
PVOID
|
PVOID
|
||||||
|
@ -136,7 +553,7 @@ RtlAllocateHeap(
|
||||||
{
|
{
|
||||||
PVOID ptr;
|
PVOID ptr;
|
||||||
|
|
||||||
ptr = MmHeapAlloc(Size);
|
ptr = HeapAllocate(FrLdrDefaultHeap, Size, ' ltR');
|
||||||
if (ptr && (Flags & HEAP_ZERO_MEMORY))
|
if (ptr && (Flags & HEAP_ZERO_MEMORY))
|
||||||
{
|
{
|
||||||
RtlZeroMemory(ptr, Size);
|
RtlZeroMemory(ptr, Size);
|
||||||
|
@ -152,6 +569,7 @@ RtlFreeHeap(
|
||||||
IN ULONG Flags,
|
IN ULONG Flags,
|
||||||
IN PVOID HeapBase)
|
IN PVOID HeapBase)
|
||||||
{
|
{
|
||||||
MmHeapFree(HeapBase);
|
HeapFree(FrLdrDefaultHeap, HeapBase, ' ltR');
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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)
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
@ -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
|
|
|
@ -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 );
|
|
||||||
}
|
|
|
@ -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);
|
|
Loading…
Add table
Add a link
Reference in a new issue