Jump to content


Photo

Oz_paulb's Lba48 Code


  • Please log in to reply
1 reply to this topic

#1 ldotsfan

ldotsfan

    X-S Messiah

  • Dev/Contributor
  • PipPipPipPipPipPipPip
  • 3,100 posts
  • Xbox Version:v1.1
  • 360 version:unknown

Posted 03 April 2010 - 02:18 PM

Copyright
---------

The entire contents of this archive (source code to patch, utilities, various kerneldefs.inc files)
are Copyright Paul Bartholomew.

patch.asm

CODE

PATCHCODE_VERSION    equ    2

%include "kerneldefs.inc"
%include "patchseg.inc"

CODE_SIZE        equ    0x8000
HIGH_LOW_DIFF    equ    (HIGHCODE_BASE - LOWCODE_BASE)

PATCH_MAGIC_ID    equ    0xcafebabe

DEF_PARTMETHOD_ONLY_STANDARD_PARTITIONS            equ    0
DEF_PARTMETHOD_PART6_REST_OF_DRIVE                equ    1
DEF_PARTMETHOD_PART6_UNDER_137GB_PART7_REST_OF_DRIVE    equ    2
DEF_PARTMETHOD_PART6_UNDER_137GB_NO_PART7            equ    3


BITS    32
    cpu    586

    segment    code

    org    HIGHCODE_BASE

; ofs=00000000
HIGHCODE_magic_id:
    dd    PATCH_MAGIC_ID
HIGHCODE_version_id:
    dd    PATCHCODE_VERSION

HIGHCODE_def_partition_method:
;    db    DEF_PARTMETHOD_PART6_REST_OF_DRIVE
    db    DEF_PARTMETHOD_PART6_UNDER_137GB_PART7_REST_OF_DRIVE

HIGHCODE_ignore_HD_part_table:
    db    0

;more flag bytes
    times 2 db 0

HIGHCODE_partition_table_offset:
    dd    (HIGHCODE_Partition_table - HIGHCODE_BASE)

    times 48 db 0

; jump table

; ofs=00000040
HIGHCODE_DiscardINITSection_hook:
    jmp    HIGHCODE_DiscardINITSection_hook_handler

; ofs=00000045
HIGHCODE_DiskCreate__getsize_hook:
    jmp    HIGHCODE_DiskCreate__getsize_hook_handler

; ofs=0000004a
HIGHCODE_PartitionCreate_hook:
    jmp    HIGHCODE_PartitionCreate_hook_handler

; ofs=0000004f
HIGHCODE_IDESetupReadWrite_hook:
    jmp    HIGHCODE_IDESetupReadWrite_hook_handler

; ofs=00000054
HIGHCODE_IDESetupVerify_hook:
    jmp    HIGHCODE_IDESetupVerify_hook_handler

; ofs=00000059
HIGHCODE_DiskCreate__finalize_hook:
    jmp    HIGHCODE_DiskCreate__finalize_hook_handler

; ofs=0000005E
HIGHCODE_DiskIoControl_hook:
    jmp    HIGHCODE_DiskIoControl_hook_handler




    align    256
    db    'LBA48 support by Paul Bartholomew (oz_paulb)  ',13,10
    db    'Copyright (c) 2003 - Released under GNU Public License',13,10
    db    0
    align    64

XBOX_SWAPPART1_LBA_START    equ    0x400
XBOX_SWAPPART_LBA_SIZE        equ    0x177000
XBOX_SWAPPART2_LBA_START    equ    (XBOX_SWAPPART1_LBA_START + XBOX_SWAPPART_LBA_SIZE)
XBOX_SWAPPART3_LBA_START    equ    (XBOX_SWAPPART2_LBA_START + XBOX_SWAPPART_LBA_SIZE)

XBOX_SYSPART_LBA_START        equ    (XBOX_SWAPPART3_LBA_START + XBOX_SWAPPART_LBA_SIZE)
XBOX_SYSPART_LBA_SIZE        equ    0xfa000

XBOX_MUSICPART_LBA_START    equ    (XBOX_SYSPART_LBA_START + XBOX_SYSPART_LBA_SIZE)
XBOX_MUSICPART_LBA_SIZE        equ    0x9896b0

XBOX_STANDARD_MAX_LBA        equ    (XBOX_MUSICPART_LBA_START + XBOX_MUSICPART_LBA_SIZE)


%macro    PT_ENTRY    5
    db    %1;partition name
    dd    %2;partition flags
    dd    %3;partition LBA start
    dd    %4;partition LBA size
    dd    %5;reserved
%endmacro

_PE_OFS__part_name    equ    (0)
_PE_OFS__part_flags    equ    (16)
PE_PARTFLAGS_IN_USE    equ    0x80000000
_PE_OFS__part_lba_start    equ    (20)
_PE_OFS__part_lba_size    equ    (24)
_PE_OFS__part_reserved    equ    (28)
_PE_SIZ__part_entry    equ    (32)

MAX_PARTITIONS        equ    14
HIGHCODE_Partition_table:
HIGHCODE_Partition_table_hdr:
    db    '****PARTINFO****'
PARTITION_MAGIC_LEN    equ    ($-HIGHCODE_Partition_table_hdr)
    times 32 db 0; reserved

_PT_OFS__part_entries    equ    ($-HIGHCODE_Partition_table)

    PT_ENTRY    'XBOX MUSIC      ',PE_PARTFLAGS_IN_USE,XBOX_MUSICPART_LBA_START,XBOX_MUSICPART_LBA_SIZE,0
    PT_ENTRY    'XBOX SYSTEM     ',PE_PARTFLAGS_IN_USE,XBOX_SYSPART_LBA_START,XBOX_SYSPART_LBA_SIZE,0
    PT_ENTRY    'XBOX GAME SWAP 1',PE_PARTFLAGS_IN_USE,XBOX_SWAPPART1_LBA_START,XBOX_SWAPPART_LBA_SIZE,0
    PT_ENTRY    'XBOX GAME SWAP 2',PE_PARTFLAGS_IN_USE,XBOX_SWAPPART2_LBA_START,XBOX_SWAPPART_LBA_SIZE,0
    PT_ENTRY    'XBOX GAME SWAP 3',PE_PARTFLAGS_IN_USE,XBOX_SWAPPART3_LBA_START,XBOX_SWAPPART_LBA_SIZE,0
HIGHCODE_Partition_table_first_available:
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
    PT_ENTRY    '                ',0,0,0,0
PARTITION_TABLE_SIZE    equ    ($-HIGHCODE_Partition_table)


    times 0x90 db 0; reserved


    align    64

HIGHCODE_DiscardINITSection_hook_handler:
    xor    eax,eax
    mov    dword [LOWCODE_BASE],eax; clear 'magic' at destination

    mov    esi, HIGHCODE_BASE+4
    mov    edi, LOWCODE_BASE+4
    mov    ecx, (CODE_SIZE/4)-1
    rep movsd            ; copy all but 'magic'

    mov    eax,dword [HIGHCODE_BASE]
    mov    dword [LOWCODE_BASE],eax; copy 'magic' last

    jmp    (LOWCODE_DiscardINITSection_hook_continue - HIGH_LOW_DIFF)

    align    16

LOWCODE_DiscardINITSection_hook_continue:
    call    FUNCADDR_DoDiscardINITSection+HIGH_LOW_DIFF
    jmp    ADDR_DiscardINITSection_hook_continue+HIGH_LOW_DIFF



    align    64


BP_OFS_IDENTIFY_DEVICE_STRUCT    equ    (0-0x228)

ID_OFS__CMD_SET_SUPPORTED    equ    (83*2)
BITMASK__CMD_SET_HAS_LBA48    equ    (1<<10)

ID_OFS__TOTAL_USER_SECTORS_LBA28    equ    (60*2)

ID_OFS__TOTAL_USER_SECTORS_LBA48_LOW    equ    (100*2)
ID_OFS__TOTAL_USER_SECTORS_LBA48_HIGH    equ    (102*2)


HIGHCODE_DiskCreate__getsize_hook_handler:
    push    ebx
    push    ecx
    push    edx

    mov    eax,[ebp+BP_OFS_IDENTIFY_DEVICE_STRUCT+ID_OFS__CMD_SET_SUPPORTED]
    and    eax, BITMASK__CMD_SET_HAS_LBA48
    jnz    short .drive_supports_lba48

.no_lba48_support:
    mov    eax,[ebp+BP_OFS_IDENTIFY_DEVICE_STRUCT+ID_OFS__TOTAL_USER_SECTORS_LBA28]
    jmp    short .have_total_sectors

.drive_supports_lba48:
    mov    eax,[ebp+BP_OFS_IDENTIFY_DEVICE_STRUCT+ID_OFS__TOTAL_USER_SECTORS_LBA48_HIGH]
    test    eax,eax
    jnz    short .drive_is_huge__limit_to_32bits
    mov    eax,[ebp+BP_OFS_IDENTIFY_DEVICE_STRUCT+ID_OFS__TOTAL_USER_SECTORS_LBA48_LOW]
    jmp    short .have_total_sectors

.drive_is_huge__limit_to_32bits:
    xor    eax,eax; FIXME: should be 33 c0, generates 31 c0 (OK?)
    dec    eax

.have_total_sectors
    mov    edx,eax        ;edx holds total drive sectors
    cmp    eax,XBOX_STANDARD_MAX_LBA
    ja    .try_extra_partitions
.j_skip_extra_partitions
    jmp    .skip_extra_partitions

.try_extra_partitions

    cmp    byte [HIGHCODE_def_partition_method],DEF_PARTMETHOD_ONLY_STANDARD_PARTITIONS
    jz    short .j_skip_extra_partitions



    sub    eax,XBOX_STANDARD_MAX_LBA;eax now free space at end of drive

    mov    ebx,eax        ;ebx holds part6 size (default to all free space)
    xor    ecx,ecx        ;ecx holds part7 size (default to zero)

    cmp    edx,0x0fffffff    ;if drive isn't > 137gb, just create part6
    jbe    .create_partitions

.drive_larger_than_137gb:
    cmp    byte [HIGHCODE_def_partition_method],DEF_PARTMETHOD_PART6_REST_OF_DRIVE
    jz    .create_partitions

    mov    eax,0x0fffffff
    sub    eax,XBOX_STANDARD_MAX_LBA
    mov    ebx,eax        ;ebx holds part6 size (rest of space before 137gb)

    cmp    byte [HIGHCODE_def_partition_method],DEF_PARTMETHOD_PART6_UNDER_137GB_NO_PART7
    jz    .create_partitions

    mov    eax,edx        ;edx holds total drive sectors
    sub    eax,XBOX_STANDARD_MAX_LBA;eax now free space at end of drive
    sub    eax,ebx        ;subtract space used for part6
    mov    ecx,eax        ;ecx holds part7 size

.create_partitions

.drive_less_or_equal_to_137gb:

;ebx = part6 size
;ecx = part7 size
;edx = total drive sectors

    mov    eax,XBOX_STANDARD_MAX_LBA
    mov    [HIGHCODE_Partition_table_first_available+(0*_PE_SIZ__part_entry)+_PE_OFS__part_lba_start],eax
    mov    dword [HIGHCODE_Partition_table_first_available+(0*_PE_SIZ__part_entry)+_PE_OFS__part_lba_size],ebx

    mov    eax,'DRIV'
    mov    [HIGHCODE_Partition_table_first_available+(0*_PE_SIZ__part_entry)+_PE_OFS__part_name],eax
    mov    eax,'E F:'
    mov    [HIGHCODE_Partition_table_first_available+(0*_PE_SIZ__part_entry)+_PE_OFS__part_name+4],eax
    mov    eax,'    '
    mov    [HIGHCODE_Partition_table_first_available+(0*_PE_SIZ__part_entry)+_PE_OFS__part_name+8],eax
    mov    eax,'    '
    mov    [HIGHCODE_Partition_table_first_available+(0*_PE_SIZ__part_entry)+_PE_OFS__part_name+12],eax

    mov    eax,PE_PARTFLAGS_IN_USE
    mov    [HIGHCODE_Partition_table_first_available+(0*_PE_SIZ__part_entry)+_PE_OFS__part_flags],eax

    test    ecx,ecx
    jz    .partitions_created


    mov    eax,XBOX_STANDARD_MAX_LBA
    add    eax,ebx
    mov    [HIGHCODE_Partition_table_first_available+(1*_PE_SIZ__part_entry)+_PE_OFS__part_lba_start],eax
    mov    dword [HIGHCODE_Partition_table_first_available+(1*_PE_SIZ__part_entry)+_PE_OFS__part_lba_size],ecx

    mov    eax,'DRIV'
    mov    [HIGHCODE_Partition_table_first_available+(1*_PE_SIZ__part_entry)+_PE_OFS__part_name],eax
    mov    eax,'E P:'
    mov    [HIGHCODE_Partition_table_first_available+(1*_PE_SIZ__part_entry)+_PE_OFS__part_name+4],eax
    mov    eax,'    '
    mov    [HIGHCODE_Partition_table_first_available+(1*_PE_SIZ__part_entry)+_PE_OFS__part_name+8],eax
    mov    eax,'    '
    mov    [HIGHCODE_Partition_table_first_available+(1*_PE_SIZ__part_entry)+_PE_OFS__part_name+12],eax

    mov    eax,PE_PARTFLAGS_IN_USE
    mov    [HIGHCODE_Partition_table_first_available+(1*_PE_SIZ__part_entry)+_PE_OFS__part_flags],eax

.partitions_created:

.skip_extra_partitions


.partitions_done
    mov    eax,edx
    pop    edx
    pop    ecx
    pop    ebx
    jmp    ADDR_DiskCreate__getsize_hook_continue


    align    64


BP_OFS_PARTITION_SIZE_IN_BYTES_LOW    equ    (0-0x20)
BP_OFS_PARTITION_SIZE_IN_BYTES_HIGH    equ    (0-0x1c)

HIGHCODE_PartitionCreate_hook_handler:
    push    edi
    push    esi
    push    ebx
    push    ecx
    push    edx

    mov    edi,0
    mov    esi,HIGHCODE_Partition_table-HIGH_LOW_DIFF
    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .common
.we_are_highcode:
    mov    edi,1
    mov    esi,HIGHCODE_Partition_table
.common
    test    ebx,ebx
    jz    short    .exit_failure

    cmp    ebx,MAX_PARTITIONS
    ja    short .exit_failure

    add    esi,_PT_OFS__part_entries

    mov    eax,ebx
    dec    eax
    mov    ecx,_PE_SIZ__part_entry
    mul    ecx
    add    esi,eax

    mov    eax,dword [esi+_PE_OFS__part_flags]
    and    eax,PE_PARTFLAGS_IN_USE
    test    eax,eax
    jz    short .exit_failure

    mov    eax,dword [esi+_PE_OFS__part_lba_size]
    mov    ecx,512
    mul    ecx
    mov    [ebp+BP_OFS_PARTITION_SIZE_IN_BYTES_LOW],eax
    mov    [ebp+BP_OFS_PARTITION_SIZE_IN_BYTES_HIGH],edx

    mov    eax,dword [esi+_PE_OFS__part_lba_start]


.exit_ok:
    pop    edx
    pop    ecx
    pop    ebx
    pop    esi

    %if    PartitionCreate_return_in_ecx > 0
        mov    ecx,eax
    %endif

    test    edi,edi
    jz    short .exit_ok_lowcode
.exit_ok_highcode:
    pop    edi
    jmp    ADDR_PartitionCreate_hook_continue
.exit_ok_lowcode:
    pop    edi
    jmp    ADDR_PartitionCreate_hook_continue+HIGH_LOW_DIFF

.exit_failure:
    pop    edx
    pop    ecx
    pop    ebx
    pop    esi

    mov    eax,0xc0000034

    test    edi,edi
    jz    short .exit_failure_lowcode
.exit_failure_highcode:
    jmp    ADDR_PartitionCreate_hook_continue_err
.exit_failure_lowcode:
    jmp    ADDR_PartitionCreate_hook_continue_err+HIGH_LOW_DIFF




IDE_REG_SEC_COUNT    equ    0x1f2
IDE_REG_LBA_LOW    equ    0x1f3
IDE_REG_LBA_MID    equ    0x1f4
IDE_REG_LBA_HIGH    equ    0x1f5
IDE_REG_DEVICE    equ    0x1f6
IDE_REG_COMMAND    equ    0x1f7

IDE_CMD_READ_DMA    equ    0xc8
IDE_CMD_READ_DMA_EXT    equ    0x25
IDE_CMD_WRITE_DMA    equ    0xca
IDE_CMD_WRITE_DMA_EXT    equ    0x35
IDE_CMD_READ_VERIFY_SECTORS    equ    0x40
IDE_CMD_READ_VERIFY_SECTORS_EXT    equ    0x42

IO_BUSMASTER_REG    equ    0xff60
IO_BUSMASTER_CMD_READ    equ    0x09
IO_BUSMASTER_CMD_WRITE    equ    0x01

IRQL_VALUE_RET    equ    2

ESI_OFS_READ_OR_WRITE_FLAG    equ    0
RWFLAG_IS_READ            equ    2
ESI_OFS_NUM_BYTES            equ    4
ESI_OFS_LBA                equ    12
ESI_OFS_LBA_LOW            equ    (ESI_OFS_LBA+0)
ESI_OFS_LBA_MID            equ    (ESI_OFS_LBA+1)
ESI_OFS_LBA_HIGH            equ    (ESI_OFS_LBA+2)
ESI_OFS_LBA_XHIGH            equ    (ESI_OFS_LBA+3)




    align    64
HIGHCODE_IDESetupReadWrite_hook_handler:
    push    eax
    push    ebx
    push    edx
    push    esi
    push    edi

    mov    eax,edi;byte count
    shr    eax,9;convert to sector count
    mov    edi,eax

    mov    eax,dword [VARADDR_TotalHardDriveSectors]
    and    eax,0xf0000000
    test    eax,eax
    jz    .is_lba28

    mov    eax,edi;num sectors
    add    eax,dword [esi+ESI_OFS_LBA]
    and    eax,0xf0000000
    test    eax,eax
    jz    short .is_lba28

.is_lba48:
    mov    dx,IDE_REG_SEC_COUNT
    mov    eax,edi
    xchg    ah,al
    out    dx,al        ;COUNTREG (15:8) = high(sector count)
    xchg    ah,al
    out    dx,al        ;COUNTREG (7:0) = low(sector count)


    mov    dx,IDE_REG_LBA_LOW
    mov    al,byte [esi+ESI_OFS_LBA_XHIGH]
    out    dx,al        ;LBAREG (31:24) = LBA (31:24)
    mov    al,byte [esi+ESI_OFS_LBA_LOW]
    out    dx,al        ;LBAREG (7:0) = LBA (7:0)

    mov    dx,IDE_REG_LBA_MID
    xor    al,al
    out    dx,al        ;LBAREG (39:32) = 0
    mov    al,byte [esi+ESI_OFS_LBA_MID]
    out    dx,al        ;LBAREG (15:8) = LBA (15:8)

    mov    dx,IDE_REG_LBA_HIGH
    xor    al,al
    out    dx,al        ;LBAREG (47:40) = 0
    mov    al,byte [esi+ESI_OFS_LBA_HIGH]
    out    dx,al        ;LBAREG (23:16) = LBA (23:16)

    mov    al,0x40
    mov    dx,IDE_REG_DEVICE
    out    dx,al


    cmp    byte [esi+ESI_OFS_READ_OR_WRITE_FLAG],RWFLAG_IS_READ
    jnz    short    .is_write_lba48


.is_read_lba48:
    mov    al,IDE_CMD_READ_DMA_EXT
    mov    cl,IO_BUSMASTER_CMD_READ
    jmp    short .write_ide_rw_command

.is_write_lba48:
    mov    al,IDE_CMD_WRITE_DMA_EXT
    mov    cl,IO_BUSMASTER_CMD_WRITE
    jmp    short .write_ide_rw_command



.is_lba28:
    mov    eax,edi
    mov    dx,IDE_REG_SEC_COUNT
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_LOW]
    mov    dx,IDE_REG_LBA_LOW
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_MID]
    mov    dx,IDE_REG_LBA_MID
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_HIGH]
    mov    dx,IDE_REG_LBA_HIGH
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_XHIGH]
    and    al,0x0f
    or    al,0xe0
    mov    dx,IDE_REG_DEVICE
    out    dx,al

    cmp    byte [esi+ESI_OFS_READ_OR_WRITE_FLAG],RWFLAG_IS_READ
    jnz    short    .is_write_lba28


.is_read_lba28:
    mov    al,IDE_CMD_READ_DMA
    mov    cl,IO_BUSMASTER_CMD_READ
    jmp    short .write_ide_rw_command

.is_write_lba28:
    mov    al,IDE_CMD_WRITE_DMA
    mov    cl,IO_BUSMASTER_CMD_WRITE

.write_ide_rw_command
    mov    dx,IDE_REG_COMMAND
    out    dx,al

    mov    al,cl
    mov    dx,IO_BUSMASTER_REG
    out    dx,al

    pop    edi
    pop    esi
    pop    edx
    pop    ebx
    pop    eax


    pop    edi;calling code pushed these, so pop them
    pop    esi
.exit:
    mov    cl,IRQL_VALUE_RET

    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .exit_lowcode
.exit_highcode:
    jmp    ADDR_IDESetupReadWrite_hook_continue

.exit_lowcode:
    jmp    ADDR_IDESetupReadWrite_hook_continue+HIGH_LOW_DIFF




    align    64
HIGHCODE_IDESetupVerify_hook_handler:
    push    eax
    push    ebx
    push    edx
    push    esi
    push    edi

    mov    eax,[esi+ESI_OFS_NUM_BYTES]
    shr    eax,9;convert to sector count
    mov    edi,eax

    mov    eax,dword [VARADDR_TotalHardDriveSectors]
    and    eax,0xf0000000
    test    eax,eax
    jz    .is_lba28

    mov    eax,edi;num sectors
    add    eax,dword [esi+ESI_OFS_LBA]
    and    eax,0xf0000000
    test    eax,eax
    jz    short .is_lba28

.is_lba48:
    mov    dx,IDE_REG_SEC_COUNT
    mov    eax,edi
    xchg    ah,al
    out    dx,al        ;COUNTREG (15:8) = high(sector count)
    xchg    ah,al
    out    dx,al        ;COUNTREG (7:0) = low(sector count)


    mov    dx,IDE_REG_LBA_LOW
    mov    al,byte [esi+ESI_OFS_LBA_XHIGH]
    out    dx,al        ;LBAREG (31:24) = LBA (31:24)
    mov    al,byte [esi+ESI_OFS_LBA_LOW]
    out    dx,al        ;LBAREG (7:0) = LBA (7:0)

    mov    dx,IDE_REG_LBA_MID
    xor    al,al
    out    dx,al        ;LBAREG (39:32) = 0
    mov    al,byte [esi+ESI_OFS_LBA_MID]
    out    dx,al        ;LBAREG (15:8) = LBA (15:8)

    mov    dx,IDE_REG_LBA_HIGH
    xor    al,al
    out    dx,al        ;LBAREG (47:40) = 0
    mov    al,byte [esi+ESI_OFS_LBA_HIGH]
    out    dx,al        ;LBAREG (23:16) = LBA (23:16)

    mov    al,0x40
    mov    dx,IDE_REG_DEVICE
    out    dx,al

    mov    al,IDE_CMD_READ_VERIFY_SECTORS_EXT
    jmp    short .write_ide_command



.is_lba28:
    mov    eax,edi
    mov    dx,IDE_REG_SEC_COUNT
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_LOW]
    mov    dx,IDE_REG_LBA_LOW
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_MID]
    mov    dx,IDE_REG_LBA_MID
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_HIGH]
    mov    dx,IDE_REG_LBA_HIGH
    out    dx,al

    mov    al,byte [esi+ESI_OFS_LBA_XHIGH]
    and    al,0x0f
    or    al,0xe0
    mov    dx,IDE_REG_DEVICE
    out    dx,al

    mov    al,IDE_CMD_READ_VERIFY_SECTORS

.write_ide_command
    mov    dx,IDE_REG_COMMAND
    out    dx,al

    pop    edi
    pop    esi
    pop    edx
    pop    ebx
    pop    eax

.exit:
    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .exit_lowcode
.exit_highcode:
    jmp    ADDR_IDESetupVerify_hook_continue

.exit_lowcode:
    jmp    ADDR_IDESetupVerify_hook_continue+HIGH_LOW_DIFF




    align    64
HIGHCODE_DiskCreate__finalize_hook_handler:

    call    FUNCADDR_IncrementBootCounter

    cmp    byte [HIGHCODE_ignore_HD_part_table],0
    jz    short .read_partition_table
    jmp    .exit

.read_partition_table
    call    HIGHCODE_read_partition_sector
    test    eax,eax
    jnz    short .exit

    mov    esi,HIGHCODE_Partition_table_hdr
    mov    edi,HIGHCODE_partition_iobuf
    mov    ecx,(PARTITION_MAGIC_LEN/4)
    repe    cmpsd
    jnz    short    .exit

    mov    esi,HIGHCODE_partition_iobuf
    mov    edi,HIGHCODE_Partition_table_hdr
    mov    ecx,PARTITION_TABLE_SIZE
    rep    movsb

.exit
    mov    edi,HIGHCODE_partition_iobuf
    mov    ecx,(512/4)
    xor    eax,eax
    rep    stosd

    jmp    ADDR_DiskCreate__finalize_hook_continue




;typedef struct tagANSI_STRING {
;    USHORT    Length;
;    USHORT    MaximumLength;
;    PCHAR    Buffer;
;} ANSI_STRING;

struc    ANSI_STRING
    .Length    resw    1
    .MaximumLength    resw    1
    .Buffer    resd    1
    .Size:
endstruc

;typedef struct tagOBJECT_ATTRIBUTES {
;    HANDLE    RootDirectory;
;    ANSI_STRING    *ObjectName;
;    ULONG    Attributes;
;} OBJECT_ATTRIBUTES;

struc    OBJECT_ATTRIBUTES
    .RootDirectory    resd    1
    .ObjectName    resd    1
    .Attributes    resd    1
    .Size:
endstruc

;typedef struct tagIO_STATUS_BLOCK {
;    union {
;        unsigned int    Status;
;        PVOID    Pointer;
;    } u1;
;    ULONG_PTR    Information;
;} IO_STATUS_BLOCK;

struc    IO_STATUS_BLOCK
    .u1    resd    1
    .Information    resd    1
    .Size:
endstruc

struc HANDLE
    .Handle    resd    1
    .Size:
endstruc

struc LARGE_INTEGER
    .QuadPart    resd    2
    .Size:
endstruc



HIGHCODE_read_partition_sector:
.var_handle    equ    (0-HANDLE.Size)
.var_byte_offset    equ    (.var_handle-LARGE_INTEGER.Size)
.var_io_stat_block    equ    (.var_byte_offset-IO_STATUS_BLOCK.Size)
.var_obj_attr    equ    (.var_io_stat_block-OBJECT_ATTRIBUTES.Size)
.var_a_path    equ    (.var_obj_attr-ANSI_STRING.Size)
.stack_adjust    equ    .var_a_path
    push    ebp
    mov    ebp,esp
    add    esp,.stack_adjust

;    RtlInitAnsiString(&a_path, "\\Device\\Harddisk0\\partition0");

    push    .raw_partition_path
    lea    eax,[ebp+.var_a_path]
    push    eax
    call    FUNCADDR_RtlInitAnsiString

;    obj_attr.RootDirectory = 0;
    xor    eax,eax
    mov    [ebp+.var_obj_attr+OBJECT_ATTRIBUTES.RootDirectory],eax

;    obj_attr.ObjectName = &a_path;
    lea    eax,[ebp+.var_a_path]
    mov    [ebp+.var_obj_attr+OBJECT_ATTRIBUTES.ObjectName],eax

;    obj_attr.Attributes = 0x40;
    mov    dword [ebp+.var_obj_attr+OBJECT_ATTRIBUTES.Attributes],0x40

;    NtOpenFile(&handle, 0x80100000, &obj_attr, &io_stat_block, 3, 0x10);
    push    0x10
    push    3
    lea    eax,[ebp+.var_io_stat_block]
    push    eax
    lea    eax,[ebp+.var_obj_attr]
    push    eax
    push    0x80100000
    lea    eax,[ebp+.var_handle]
    push    eax
    call    FUNCADDR_NtOpenFile
    cmp    eax,0
    jl    .j_exit_error
    jmp    short    .continue
.j_exit_error:
    jmp    .exit_error

.continue:
;    byte_offset.QuadPart = 0;
    mov    dword [ebp+.var_byte_offset+LARGE_INTEGER.QuadPart],0
    mov    dword [ebp+.var_byte_offset+LARGE_INTEGER.QuadPart+4],0

;    NtReadFile(handle, 0, 0, 0, &io_stat_block, (PVOID)part_buf, sizeof(part_buf), &byte_offset);
    lea    eax,[ebp+.var_byte_offset]
    push    eax
    push    0x200
    mov    eax,HIGHCODE_partition_iobuf
    push    eax
    lea    eax,[ebp+.var_io_stat_block]
    push    eax
    push    0
    push    0
    push    0
    mov    eax,[ebp+.var_handle]
    push    eax
    call    FUNCADDR_NtReadFile
    cmp    eax,0
    jl    short .exit_error_close

;    NtClose(handle);
    mov    eax,[ebp+.var_handle]
    push    eax
    call    FUNCADDR_NtClose
    cmp    eax,0
    jl    short .exit_error
    jmp    short .exit_ok    

.exit_error_close
    mov    eax,[ebp+.var_handle]
    push    eax
    call    FUNCADDR_NtClose
.exit_error:
    mov    eax,-1
    jmp    short .exit

.exit_ok:
    xor    eax,eax
.exit:
    leave
    ret    0


.raw_partition_path    db    '\Device\Harddisk0\partition0',0
    align    64
HIGHCODE_partition_iobuf:    times 512 db 0




BP_OFS_IOCTL_ARG_DEVICE    equ    8
BP_OFS_IOCTL_ARG_PACKET    equ    0x0c

IOCTL_CMD_DO_START_IO        equ    0x4d028
IOCTL_CMD_GET_DRIVE_GEOMETRY    equ    0x70000
IOCTL_CMD_DO_VERIFY        equ    0x70014
IOCTL_CMD_GET_PARTITION_INFO    equ    0x74004
IOCTL_CMD_LBA48_ACCESS        equ    0xcafebabe

IOCTL_LBA48_SUBCMD_GET_INFO    equ    0x0

IOCTL_ARG_OFS_CMD_PACKET    equ    0x5c
IOCTL_ARG_OFS_OUT_PTR        equ    0x30
IOCTL_ARG_OFS_OUT_ACTUAL    equ    0x14

IOCTL_CMD_OFS_COMMAND        equ    0x10
IOCTL_CMD_OFS_OUT_BUFLEN    equ    0x4
IOCTL_CMD_OFS_IN_BUFLEN        equ    0x0c
IOCTL_CMD_OFS_IN_PTR        equ    0x8


    align    64
HIGHCODE_DiskIoControl_hook_handler:
    push    ebp
    mov    ebp,esp
    push    esi

;
;when we get here:
;[ebp+BP_OFS_IOCTL_ARG_DEVICE]    device struct?
;[ebp+BP_OFS_IOCTL_ARG_PACKET]    ioctl arg struct
;

    mov    esi,[ebp+BP_OFS_IOCTL_ARG_PACKET]
    mov    eax,[esi+IOCTL_ARG_OFS_CMD_PACKET]
    mov    ecx,[eax+IOCTL_CMD_OFS_COMMAND]
    push    edi

    cmp    ecx,IOCTL_CMD_LBA48_ACCESS
    jnz    short .standard_ioctl_code
    jmp    .got_my_ioctl_code

.standard_ioctl_code:
    sub    ecx,IOCTL_CMD_DO_START_IO
    jz    short .handle_start_io
    sub    ecx,(IOCTL_CMD_GET_DRIVE_GEOMETRY-IOCTL_CMD_DO_START_IO)
    jz    short .handle_get_drive_geometry
    sub    ecx,(IOCTL_CMD_DO_VERIFY-IOCTL_CMD_GET_DRIVE_GEOMETRY)
    jz    short .handle_do_verify
    sub    ecx,(IOCTL_CMD_GET_PARTITION_INFO-IOCTL_CMD_DO_VERIFY)
    jnz    short .unknown_ioctl_code
    jmp    .handle_get_partition_info

.unknown_ioctl_code:
    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .unknown_ioctl_code_lowcode
.unknown_ioctl_code_highcode:
    jmp    ADDR_DiskIoControl__unknown_ioctl_code
.unknown_ioctl_code_lowcode:
    jmp    ADDR_DiskIoControl__unknown_ioctl_code+HIGH_LOW_DIFF



.handle_start_io:
    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .handle_start_io_lowcode
.handle_start_io_highcode:
    jmp    ADDR_DiskIoControl__do_start_io
.handle_start_io_lowcode:
    jmp    ADDR_DiskIoControl__do_start_io+HIGH_LOW_DIFF



.handle_get_drive_geometry:
    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .handle_get_drive_geometry_lowcode
.handle_get_drive_geometry_highcode:
    jmp    ADDR_DiskIoControl__get_drive_geometry
.handle_get_drive_geometry_lowcode:
    jmp    ADDR_DiskIoControl__get_drive_geometry+HIGH_LOW_DIFF



.handle_do_verify:
    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .handle_do_verify_lowcode
.handle_do_verify_highcode:
    jmp    ADDR_DiskIoControl__do_verify
.handle_do_verify_lowcode:
    jmp    ADDR_DiskIoControl__do_verify+HIGH_LOW_DIFF



.handle_get_partition_info:
    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .handle_get_partition_info_lowcode
.handle_get_partition_info_highcode:
    jmp    ADDR_DiskIoControl__get_partition_info
.handle_get_partition_info_lowcode:
    jmp    ADDR_DiskIoControl__get_partition_info+HIGH_LOW_DIFF



.got_my_ioctl_code:

;
;when we get here:
;[ebp+BP_OFS_IOCTL_ARG_DEVICE]    device struct?
;[ebp+BP_OFS_IOCTL_ARG_PACKET]    ioctl arg struct
;[ioctl struct+0x5c]            ioctl transfer packet (in data/len, out data/len, command)
;

    push    esi
    push    edi

    mov    eax,[ebp+BP_OFS_IOCTL_ARG_PACKET]
    mov    esi,[eax+IOCTL_ARG_OFS_CMD_PACKET]

    cmp    dword [esi+IOCTL_CMD_OFS_IN_BUFLEN],4
    jnb    short .inbuf_big_enough

    mov    eax,0xc0000004;input length wrong
    jmp    short .exit

.inbuf_big_enough:
    cmp    dword [esi+IOCTL_CMD_OFS_OUT_BUFLEN],28
    jnb    short .outbuf_big_enough

    mov    eax,0xc0000023;buffer too small
    jmp    short .exit

.outbuf_big_enough:
    mov    edi,[esi+IOCTL_CMD_OFS_IN_PTR]
    cmp    dword [edi],IOCTL_LBA48_SUBCMD_GET_INFO
    jz    short .get_info_cmd

    mov    eax,0xc0000010;invalid request
    jmp    short .exit

.get_info_cmd:
    mov    edi,[eax+IOCTL_ARG_OFS_OUT_PTR]
    mov    dword [edi],0xcafebabe
    mov    dword [edi+4],0xbabeface
    mov    dword [edi+8],PATCHCODE_VERSION
    mov    dword [edi+12],LOWCODE_BASE
    mov    dword [edi+16],HIGHCODE_BASE
    mov    dword [edi+20],PATCHSEG_SIZE
    mov    dword [edi+24],(HIGHCODE_Partition_table-HIGHCODE_BASE)

    mov    dword [eax+IOCTL_ARG_OFS_OUT_ACTUAL],28
    xor    eax,eax

.exit:
    pop    edi
    pop    esi
    mov    edi,eax

    cmp    dword [HIGHCODE_magic_id-HIGH_LOW_DIFF],PATCH_MAGIC_ID
    jz    short .exit_lowcode
.exit_highcode:
    jmp    ADDR_DiskIoControl__return
.exit_lowcode:
    jmp    ADDR_DiskIoControl__return+HIGH_LOW_DIFF






Edited by ldotsfan, 03 April 2010 - 02:20 PM.


#2 ldotsfan

ldotsfan

    X-S Messiah

  • Dev/Contributor
  • PipPipPipPipPipPipPip
  • 3,100 posts
  • Xbox Version:v1.1
  • 360 version:unknown

Posted 03 April 2010 - 02:30 PM

CODE

Making space in the Xbox KERNEL for patches:
============================================

This is a quick description of the method I used for expanding the Xbox
KERNEL (xboxkrnl.img) to make room for the LBA48 patches.

Basically, all I'm doing is increasing the size of the image by adjusting
the .exe "PE header", and adjusting the address/sizes of some segments.

This gets me a 'spare' chunk of memory at the end of the KERNEL, which
(after KERNEL initialization is finished) I move down in memory so it
won't get discarded as part of the "INIT" section (normal Xbox KERNEL
does this 'discard' after initialization)

All specific offsets used in my examples are for the original 3944 KERNEL,
but would work with any other KERNEL version.

Here's a picture of what the standard 3944 KERNEL image looks like in
memory when it's decompressed (lowest address at bottom):



    800A8180 +--------------------+
             |                    |
             |                    |
             |                    |
             |                    |
             |                    |
             |                    |
             |    INIT segment    |
             |                    |
             |   (size = 06BE60)  |
             |                    |
             |                    |
             |                    |
             |                    |
    8003C320 +====================+ (above here will be discarded after init)
             |  IDEXPRDT segment  |
             |   (size = 000120)  |
    8003C200 +--------------------+
             |   STICKY segment   |
             |   (size = 000480)  |
    8003BC00 +--------------------+
             |                    |
             |    .data segment   |
             |                    |
             |   (size = 0055A0)  |
    80036660 +--------------------+
             |                    |
             |                    |
             |                    |
             |    .text segment   |
             |                    |
             |   (size = 0263C0)  |
             |                    |
             |                    |
    800102A0 +--------------------+
             |     PE header      |
             +--------------------+
             |DOS exe header/stub |
    80010000 +--------------------+


I chose to add 32Kbytes (arbitrary size) to the KERNEL.  I did this by increasing
the file size of 'xboxkrnl.img' by 32K (just padding end of file with zeros), then
adjusting the PE header's 'image size' to reflect the new size.

This is what the new picture looks like:

    800B0180 +--------------------+
             |                    |
             |     extra space    |
             |(not really segment)|
             |                    |
             |   (size = 008000)  |
             |                    |
    800A8180 +--------------------+
             |                    |
             |                    |
             |                    |
             |                    |
             |                    |
             |                    |
             |    INIT segment    |
             |                    |
             |   (size = 06BE60)  |
             |                    |
             |                    |
             |                    |
             |                    |
    8003C320 +====================+ (above here will be discarded after init)
             |  IDEXPRDT segment  |
             |   (size = 000120)  |
    8003C200 +--------------------+
             |   STICKY segment   |
             |   (size = 000480)  |
    8003BC00 +--------------------+
             |                    |
             |    .data segment   |
             |                    |
             |   (size = 0055A0)  |
    80036660 +--------------------+
             |                    |
             |                    |
             |                    |
             |    .text segment   |
             |                    |
             |   (size = 0263C0)  |
             |                    |
             |                    |
    800102A0 +--------------------+
             |     PE header      |
             +--------------------+
             |DOS exe header/stub |
    80010000 +--------------------+


The problem with this picture is that my 'extra space' will be discarded along with
the INIT section once initialization is complete.  What is needed is a way to get
code just after the "IDEXPRDT" section (the highest non-discarded section), and
have it included in what the KERNEL decides to "keep".

We can't easily 'insert' a segment, because of absolute addresses used to access
memory higher up in the KERNEL.

So, I decided on this: I would put 'patch' code into my 'extra space' at the end.
Any "INIT" code that I want to patch be patched to call/jmp directly into the
'extra space' region without problems (because as long as INIT section is there,
our 'extra space' region will also be there).

At the time the KERNEL decides to discard the INIT section (and above), I moved
my 32K 'extra space' to be just above the IDEXPRDT section.  I needed to tell
the KERNEL that it should leave that 32K alone.  The easiest way to do this was
to patch the segment table in the "PE header" to 'lie' to the KERNEL about the
size/location of segments (the KERNEL decides where to start discarding memory
based on the starting address of the "INIT" section").  The address of this
'discard INIT section' code is 0x8001FC9F, called from 0x80016C0F (KERNEL 3944).

I adjusted the size of "IDEXPRDT" to be 32K larger (and made it Executable), and
the starting address of "INIT" to be 32K higher.  I left the size of "INIT" alone,
meaning it will consume my 'extra space' as part of the INIT segment.  Note that
by adjusting the end/size of IDEXPRDT and the start of INIT we are not actually
changing what is in memory at those locations - the KERNEL image is loaded into
memory as a 'flat' image.  We're just adjusting the segments so the KERNEL's
"discard INIT section" works the way we want it to.

Here's the new picture:

    800B0180 +--------------------+
             |                    |
             |     extra space    |
             | (part of INIT seg) |
             |     "HIGHCODE"     |
             |   (size = 008000)  |
             |                    |
    800A8180 +- - - - - - - - - - +
             |                    |
             |                    |
             |                    |
             |                    |
             |    INIT segment    |
             |                    |
             |   (size = 06BE60)  |
             |                    |
             |                    |
             |                    |
    80044320 +====================+ (above here will be discarded after init)
             |                    |
             |  room for patch    |
             |  code after INIT   |
             | section discarded  |
             |     "LOWCODE"      |
    8003C320 +- - - - - - - - - - +
             |  IDEXPRDT segment  |
             |   (size = 008120)  |
    8003C200 +--------------------+
             |   STICKY segment   |
             |   (size = 000480)  |
    8003BC00 +--------------------+
             |                    |
             |    .data segment   |
             |                    |
             |   (size = 0055A0)  |
    80036660 +--------------------+
             |                    |
             |                    |
             |                    |
             |    .text segment   |
             |                    |
             |   (size = 0263C0)  |
             |                    |
             |                    |
    800102A0 +--------------------+
             |     PE header      |
             +--------------------+
             |DOS exe header/stub |
    80010000 +--------------------+


From this point on, when talking about my 'extra space/patch' regions, I'll refer to the
one at the end of memory (starting at 800A8180 in KERNEL 3944) as "HIGHCODE", and the
lower one (where it gets memcpy'd to at 8003C320) as "LOWCODE".

As I said above, at address 0x80016C0F there's a "call" to a function that discards the
INIT section.  We need to hook-into that call, and move our code from "HIGHCODE" to
"LOWCODE" before the memory is discarded.

I do this by replacing the "call" at 0x80016C0F to a "jmp" to a function in "HIGHCODE".
This function copies the 32K from "HIGHCODE" to "LOWCODE", them "jmp's" down to a
'continuation' function in "LOWCODE".  This 'continuation' function performs the same
"call" that used to be at 0x8003C320 (discarding INIT memory), then "jmp's" back
to 0x8003C325 (just after the original "call", continuing execution where it left off).


So, memory now looks like this:


    80044320 +--------------------+
             |                    |
             |                    |
             |     "LOWCODE"      |
             |                    |
             |                    |
    8003C320 +- - - - - - - - - - +
             |  IDEXPRDT segment  |
             |   (size = 008120)  |
    8003C200 +--------------------+
             |   STICKY segment   |
             |   (size = 000480)  |
    8003BC00 +--------------------+
             |                    |
             |    .data segment   |
             |                    |
             |   (size = 0055A0)  |
    80036660 +--------------------+
             |                    |
             |                    |
             |                    |
             |    .text segment   |
             |                    |
             |   (size = 0263C0)  |
             |                    |
             |                    |
    800102A0 +--------------------+
             |     PE header      |
             +--------------------+
             |DOS exe header/stub |
    80010000 +--------------------+


There's still one problem to deal with.  As I said above, code in the "INIT" section
can make direct calls/jmps into "HIGHCODE", because it knows that it's there as long
as "INIT" is there.  But, what about code in ".text"?  It's not that simple.

Code in ".text" may be executing at the same time "INIT" is still in memory (and
*before* "HIGHCODE" has been copied down to "LOWCODE").  How does ".text" code know
where to make its "patch" jmps/calls?

I solved this by putting a 'magic #' (0xcafebabe) at the start of "HIGHCODE".  This
number won't be at the start of the "LOWCODE" region of memory until after the
copy from "HIGHCODE" to "LOWCODE".

Code in ".text" can test the first word at the start of "LOWCODE" for this magic
value.  If the value is there, then it should jmp/call into "LOWCODE".  Otherwise,
it should jmp/call into "HIGHCODE".  Since it's the same binary image, the address
offset between the two calls will always be a fixed number.  So, the sequence can
look like:

HIGHCODE_BASE    equ    0x8003c320
LOWCODE_BASE    equ    0x800a8180
HIGH_LOW_DIFF    equ    (HIGHCODE_BASE - LOWCODE_BASE)

MAGIC_VAL    equ    0xcafebabe


;patch call here

    cmp    dword [LOWCODE_BASE],MAGIC_VAL
    jnz    .must_be_highcode
    jmp    LOWCODE_PATCHFUNC_ADDRESS
.must_be_highcode:
    jmp    (LOWCODE_PATCHFUNC_ADDRESS + HIGH_LOW_DIFF)


Code inside the patch segment that wants to 'jmp/call' back into '.text' functions
needs to use similar logic (all my code was assembled with an 'origin' of the
"HIGHCODE" address):

    cmp    dword [LOWCODE_BASE],MAGIC_VAL
    jnz    .I_must_be_running_from_highcode_address

;we're running in LOWCODE region, but were assembled as HIGHCODE,
;so relative jump target address should be adjusted
    jmp    (text_FUNCTION_ADDRESS + HIGH_LOW_DIFF)

.I_must_be_running_from_highcode_address:
    jmp    text_FUNCTION_ADDRESS




That's pretty much it.  So far, it seems to be working OK.  The goofy-ness with the
HIGHCODE vs LOWCODE calls makes things a bit 'clunky', but I think that the benefit
of being able to increase the size of the KERNEL by an arbitrary amount far outweighs
this limitation.

- Paulb






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users