From 580c71ea02736d1cd6aecdd484f3879c7b38db0b Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sat, 25 Apr 2020 20:33:28 +0300 Subject: [PATCH] Utilities: Move Duet tools to DuetPkg repository --- Utilities/BootInstall/bootsrc/Makefile | 20 - Utilities/BootInstall/bootsrc/boot0.nasm | 739 -------------------- Utilities/BootInstall/bootsrc/boot1f32.nasm | 603 ---------------- Utilities/Duet/EfiLdrImage | Bin 35268 -> 0 bytes Utilities/Duet/GenPage | Bin 39476 -> 0 bytes 5 files changed, 1362 deletions(-) delete mode 100644 Utilities/BootInstall/bootsrc/Makefile delete mode 100644 Utilities/BootInstall/bootsrc/boot0.nasm delete mode 100644 Utilities/BootInstall/bootsrc/boot1f32.nasm delete mode 100755 Utilities/Duet/EfiLdrImage delete mode 100755 Utilities/Duet/GenPage diff --git a/Utilities/BootInstall/bootsrc/Makefile b/Utilities/BootInstall/bootsrc/Makefile deleted file mode 100644 index 0cc5dcc8..00000000 --- a/Utilities/BootInstall/bootsrc/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -DESTDIR ?= .. -BOOTSECTORS = boot0 boot1f32 - -BOOTSECTOR_SRCS = $(addsuffix .nasm, $(BOOTSECTORS)) -BOOTSECTOR_BINS = $(addprefix $(DESTDIR)/, $(BOOTSECTORS)) - -ifdef NASM_PREFIX -NASM=$(NASM_PREFIX)nasm -else -NASM=nasm -endif - -all: $(BOOTSECTOR_BINS) - -$(BOOTSECTOR_BINS): $(BOOTSECTOR_SRCS) - @echo "[NASM] $(@F).nasm -> $@" - @"$(NASM)" $(@F).nasm -o $@ - -clean: - rm -f $(BOOTSECTOR_BINS) *~ diff --git a/Utilities/BootInstall/bootsrc/boot0.nasm b/Utilities/BootInstall/bootsrc/boot0.nasm deleted file mode 100644 index b00a94ee..00000000 --- a/Utilities/BootInstall/bootsrc/boot0.nasm +++ /dev/null @@ -1,739 +0,0 @@ -; Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. -; -; @APPLE_LICENSE_HEADER_START@ -; -; Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights -; Reserved. This file contains Original Code and/or Modifications of -; Original Code as defined in and that are subject to the Apple Public -; Source License Version 2.0 (the "License"). You may not use this file -; except in compliance with the License. Please obtain a copy of the -; License at http://www.apple.com/publicsource and read it before using -; this file. -; -; The Original Code and all software distributed under the License are -; distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER -; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -; FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the -; License for the specific language governing rights and limitations -; under the License. -; -; @APPLE_LICENSE_HEADER_END@ -; -; Boot Loader: boot0 -; -; A small boot sector program written in x86 assembly whose only -; responsibility is to locate the active partition, load the -; partition booter into memory, and jump to the booter's entry point. -; It leaves the boot drive in DL and a pointer to the partition entry in SI. -; This version of boot0 implements hybrid GUID/MBR partition scheme support. -; -; This boot loader must be placed in the Master Boot Record. -; -; In order to coexist with a fdisk partition table (64 bytes), and -; leave room for a two byte signature (0xAA55) in the end, boot0 is -; restricted to 446 bytes (512 - 64 - 2). If boot0 did not have to -; live in the MBR, then we would have 510 bytes to work with. -; -; boot0 is always loaded by the BIOS or another booter to 0:7C00h. -; -; This code is written for the NASM assembler. -; nasm boot0.s -o boot0 -; -; Written by Tamás Kosárszky on 2008-03-10 and JrCs on 2013-05-08. -; With additions by Turbo for EFI System Partition boot support. -; - -; -; Set to 1 to enable obscure debug messages. -; -DEBUG EQU 0 - -; -; Set to 1 to enable verbose mode -; -VERBOSE EQU 0 - -; -; Various constants. -; -kBoot0Segment EQU 0x0000 -kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer -kBoot0LoadAddr EQU 0x7C00 ; boot0 load address -kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address - -kMBRBuffer EQU 0x1000 ; MBR buffer address -kLBA1Buffer EQU 0x1200 ; LBA1 - GPT Partition Table Header buffer address -kGPTABuffer EQU 0x1400 ; GUID Partition Entry Array buffer address - -kPartTableOffset EQU 0x1be -kMBRPartTable EQU kMBRBuffer + kPartTableOffset - -kSectorBytes EQU 512 ; sector size in bytes -kBootSignature EQU 0xAA55 ; boot sector signature -kFAT32BootCodeOffset EQU 0x5a ; offset of boot code in FAT32 boot sector -kBoot1FAT32Magic EQU 'BO' ; Magic string to detect our boot1f32 code - - -kGPTSignatureLow EQU 'EFI ' ; GUID Partition Table Header Signature -kGPTSignatureHigh EQU 'PART' -kGUIDLastDwordOffs EQU 12 ; last 4 byte offset of a GUID - -kPartCount EQU 4 ; number of paritions per table -kPartTypeFAT32 EQU 0x0c ; FAT32 Filesystem type -kPartTypePMBR EQU 0xee ; On all GUID Partition Table disks a Protective MBR (PMBR) - ; in LBA 0 (that is, the first block) precedes the - ; GUID Partition Table Header to maintain compatibility - ; with existing tools that do not understand GPT partition structures. - ; The Protective MBR has the same format as a legacy MBR - ; and contains one partition entry with an OSType set to 0xEE - ; reserving the entire space used on the disk by the GPT partitions, - ; including all headers. - -kPartActive EQU 0x80 ; active flag enabled -kPartInactive EQU 0x00 ; active flag disabled -kEFISystemGUID EQU 0x3BC93EC9 ; last 4 bytes of EFI System Partition Type GUID: - ; C12A7328-F81F-11D2-BA4B-00A0C93EC93B -kBasicDataGUID EQU 0xC79926B7 ; last 4 bytes of Basic Data System Partition Type GUID: - ; EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 - -; -; Format of fdisk partition entry. -; -; The symbol 'part_size' is automatically defined as an `EQU' -; giving the size of the structure. -; - struc part -.bootid resb 1 ; bootable or not -.head resb 1 ; starting head, sector, cylinder -.sect resb 1 ; -.cyl resb 1 ; -.type resb 1 ; partition type -.endhead resb 1 ; ending head, sector, cylinder -.endsect resb 1 ; -.endcyl resb 1 ; -.lba resd 1 ; starting lba -.sectors resd 1 ; size in sectors - endstruc - -; -; Format of GPT Partition Table Header -; - struc gpth -.Signature resb 8 -.Revision resb 4 -.HeaderSize resb 4 -.HeaderCRC32 resb 4 -.Reserved resb 4 -.MyLBA resb 8 -.AlternateLBA resb 8 -.FirstUsableLBA resb 8 -.LastUsableLBA resb 8 -.DiskGUID resb 16 -.PartitionEntryLBA resb 8 -.NumberOfPartitionEntries resb 4 -.SizeOfPartitionEntry resb 4 -.PartitionEntryArrayCRC32 resb 4 - endstruc - -; -; Format of GUID Partition Entry Array -; - struc gpta -.PartitionTypeGUID resb 16 -.UniquePartitionGUID resb 16 -.StartingLBA resb 8 -.EndingLBA resb 8 -.Attributes resb 8 -.PartitionName resb 72 - endstruc - -; -; Macros. -; -%macro DebugCharMacro 1 - mov al, %1 - call print_char -%endmacro - -%macro LogString 1 - mov di, %1 - call log_string -%endmacro - -%if DEBUG -%define DebugChar(x) DebugCharMacro x -%else -%define DebugChar(x) -%endif - -;-------------------------------------------------------------------------- -; Start of text segment. - - SEGMENT .text - - ORG kBoot0RelocAddr - -;-------------------------------------------------------------------------- -; Boot code is loaded at 0:7C00h. -; -start: - ; - ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack. - ; Interrupts should be off while the stack is being manipulated. - ; - cli ; interrupts off - xor ax, ax ; zero ax - mov ss, ax ; ss <- 0 - mov sp, kBoot0Stack ; sp <- top of stack - sti ; reenable interrupts - - mov es, ax ; es <- 0 - mov ds, ax ; ds <- 0 - - ; - ; Relocate boot0 code. - ; - mov si, kBoot0LoadAddr ; si <- source - mov di, kBoot0RelocAddr ; di <- destination - cld ; auto-increment SI and/or DI registers - mov cx, kSectorBytes/2 ; copy 256 words - repnz movsw ; repeat string move (word) operation - - ; - ; Code relocated, jump to start_reloc in relocated location. - ; - jmp kBoot0Segment:start_reloc - -;-------------------------------------------------------------------------- -; Start execution from the relocated location. -; -start_reloc: - - DebugChar('>') - -%if DEBUG - mov al, dl - call print_hex -%endif - - ; - ; Since this code may not always reside in the MBR, always start by - ; loading the MBR to kMBRBuffer and LBA1 to kGPTBuffer. - ; - - xor eax, eax - mov [my_lba], eax ; store LBA sector 0 for read_lba function - mov al, 2 ; load two sectors: MBR and LBA1 - mov bx, kMBRBuffer ; MBR load address - call load - jc error ; MBR load error - - ; - ; Look for the booter partition in the MBR partition table, - ; which is at offset kMBRPartTable. - ; - mov si, kMBRPartTable ; pointer to partition table - call find_boot ; will not return on success - -error: - LogString(boot_error_str) - -hang: - hlt - jmp hang - - -;-------------------------------------------------------------------------- -; Find the active (boot) partition and load the booter from the partition. -; -; Arguments: -; DL = drive number (0x80 + unit number) -; SI = pointer to fdisk partition table. -; -; Clobber list: -; EAX, BX, EBP -; -find_boot: - - ; - ; Check for boot block signature 0xAA55 following the 4 partition - ; entries. - ; - cmp WORD [si + part_size * kPartCount], kBootSignature - jne .exit ; boot signature not found. - - xor bx, bx ; BL will be set to 1 later in case of - ; Protective MBR has been found - -.start_scan: - mov cx, kPartCount ; number of partition entries per table - -.loop: - - ; - ; First scan through the partition table looking for the active - ; partition. - ; -%if DEBUG - mov al, [si + part.type] ; print partition type - call print_hex -%endif - - mov eax, [si + part.lba] ; save starting LBA of current - mov [my_lba], eax ; MBR partition entry for read_lba function - cmp BYTE [si + part.type], 0 ; unused partition? - je .continue ; skip to next entry - cmp BYTE [si + part.type], kPartTypePMBR ; check for Protective MBR - jne .tryToBootIfActive - - mov BYTE [si + part.bootid], kPartInactive ; found Protective MBR - ; clear active flag to make sure this protective - ; partition won't be used as a bootable partition. - mov bl, 1 ; Assume we can deal with GPT but try to scan - ; later if not found any other bootable partitions. - -.tryToBootIfActive: - ; We're going to try to boot a partition if it is active - cmp BYTE [si + part.bootid], kPartActive - jne .continue - - ; - ; Found boot partition, read boot sector to memory. - ; - - xor dh, dh ; Argument for loadBootSector to skip file system signature check. - call loadBootSector - jne .continue - jmp SHORT initBootLoader - -.continue: - add si, BYTE part_size ; advance SI to next partition entry - loop .loop ; loop through all partition entries - - ; - ; Scanned all partitions but not found any with active flag enabled - ; Anyway if we found a protective MBR before we still have a chance - ; for a possible GPT Header at LBA 1 - ; - dec bl - jnz .exit ; didn't find Protective MBR before - call checkGPT - -.exit: - ret ; Giving up. - - - ; - ; Jump to partition booter. The drive number is already in register DL. - ; SI is pointing to the modified partition entry. - ; -initBootLoader: - -DebugChar('J') - -%if VERBOSE - LogString(done_str) -%endif - - jmp kBoot0LoadAddr - - ; - ; Found Protective MBR Partition Type: 0xEE - ; Check for 'EFI PART' string at the beginning - ; of LBA1 for possible GPT Table Header - ; -checkGPT: - push bx - - mov di, kLBA1Buffer ; address of GUID Partition Table Header - cmp DWORD [di], kGPTSignatureLow ; looking for 'EFI ' - jne .exit ; not found. Giving up. - cmp DWORD [di + 4], kGPTSignatureHigh ; looking for 'PART' - jne .exit ; not found. Giving up indeed. - mov si, di - - ; - ; Loading GUID Partition Table Array - ; - mov eax, [si + gpth.PartitionEntryLBA] ; starting LBA of GPT Array - mov [my_lba], eax ; save starting LBA for read_lba function - mov cx, [si + gpth.NumberOfPartitionEntries] ; number of GUID Partition Array entries - mov bx, [si + gpth.SizeOfPartitionEntry] ; size of GUID Partition Array entry - - push bx ; push size of GUID Partition entry - - ; - ; Current GPT Arrays uses 128 partition entries each 128 bytes long - ; 128 entries * 128 bytes long GPT Array entries / 512 bytes per sector = 32 sectors - ; - mov al, 32 ; maximum sector size of GPT Array (hardcoded method) - - mov bx, kGPTABuffer - push bx ; push address of GPT Array - call load ; read GPT Array - pop si ; SI = address of GPT Array - pop bx ; BX = size of GUID Partition Array entry - jc error - - ; - ; Walk through GUID Partition Table Array - ; and load boot record from first supported partition. - ; - ; If it has boot signature (0xAA55) then jump to it - ; otherwise skip to next partition. - ; - -%if VERBOSE - LogString(gpt_str) -%endif - -.gpt_loop: - - mov eax, [si + gpta.PartitionTypeGUID + kGUIDLastDwordOffs] - - ; - ; Try EFI System Partition - ; - cmp eax, kEFISystemGUID ; check current GUID Partition for EFI System Partition GUID type - je .gpt_ok - - ; - ; Also try FAT2 System Partition - ; - cmp eax, kBasicDataGUID ; check current GUID Partition for Basic Data Partition GUID type - jne .gpt_continue - -.gpt_ok: - ; - ; Found a possible good partition try to boot it - ; - - mov eax, [si + gpta.StartingLBA] ; load boot sector from StartingLBA - mov [my_lba], eax - mov dh, 1 ; Argument for loadBootSector to check file system signature. - call loadBootSector - jne .gpt_continue ; no boot loader signature - - mov si, kMBRPartTable ; fake the current GUID Partition - mov [si + part.lba], eax ; as MBR style partition for boot1f32, - mov BYTE [si + part.type], kPartTypeFAT32 ; set filesystem type for cosmetic reasons - jmp SHORT initBootLoader - -.gpt_continue: - - add si, bx ; advance SI to next partition entry - loop .gpt_loop ; loop through all partition entries - -.exit: - pop bx - ret ; no more GUID partitions. Giving up. - - -;-------------------------------------------------------------------------- -; loadBootSector - Load boot sector -; -; Arguments: -; DL = drive number (0x80 + unit number) -; DH = 0 skip file system signature checking -; 1 enable file system signature checking -; [my_lba] = starting LBA. -; -; Returns: -; ZF = 0 if boot sector hasn't kBootSignature -; 1 if boot sector has kBootSignature -; -loadBootSector: - pusha - - mov al, 3 - mov bx, kBoot0LoadAddr - call load - jc error - - or dh, dh - jz .checkBootSignature - -%if VERBOSE - LogString(test_str) -%endif - - ; - ; Looking for boot1f32 magic string. - ; - mov ax, [kBoot0LoadAddr + kFAT32BootCodeOffset] - cmp ax, kBoot1FAT32Magic - jne .exit - -.checkBootSignature: - ; - ; Check for boot block signature 0xAA55 - ; - cmp WORD [kBoot0LoadAddr + kSectorBytes - 2], kBootSignature - -.exit: - - popa - - ret - - -;-------------------------------------------------------------------------- -; load - Load one or more sectors from a partition. -; -; Arguments: -; AL = number of 512-byte sectors to read. -; ES:BX = pointer to where the sectors should be stored. -; DL = drive number (0x80 + unit number) -; [my_lba] = starting LBA. -; -; Returns: -; CF = 0 success -; 1 error -; -load: - push cx - -.ebios: - mov cx, 5 ; load retry count -.ebios_loop: - call read_lba ; use INT13/F42 - jnc .exit - loop .ebios_loop - -.exit: - pop cx - ret - - -;-------------------------------------------------------------------------- -; read_lba - Read sectors from a partition using LBA addressing. -; -; Arguments: -; AL = number of 512-byte sectors to read (valid from 1-127). -; ES:BX = pointer to where the sectors should be stored. -; DL = drive number (0x80 + unit number) -; [my_lba] = starting LBA. -; -; Returns: -; CF = 0 success -; 1 error -; -read_lba: - pushad ; save all registers - mov bp, sp ; save current SP - - ; - ; Create the Disk Address Packet structure for the - ; INT13/F42 (Extended Read Sectors) on the stack. - ; - -; push DWORD 0 ; offset 12, upper 32-bit LBA - push ds ; For sake of saving memory, - push ds ; push DS register, which is 0. - mov ecx, [my_lba] ; offset 8, lower 32-bit LBA - push ecx - push es ; offset 6, memory segment - push bx ; offset 4, memory offset - xor ah, ah ; offset 3, must be 0 - push ax ; offset 2, number of sectors - - ; It pushes 2 bytes with a smaller opcode than if WORD was used - push BYTE 16 ; offset 0-1, packet size - - DebugChar('<') -%if DEBUG - mov eax, ecx - call print_hex -%endif - - ; - ; INT13 Func 42 - Extended Read Sectors - ; - ; Arguments: - ; AH = 0x42 - ; DL = drive number (80h + drive unit) - ; DS:SI = pointer to Disk Address Packet - ; - ; Returns: - ; AH = return status (sucess is 0) - ; carry = 0 success - ; 1 error - ; - ; Packet offset 2 indicates the number of sectors read - ; successfully. - ; - mov si, sp - mov ah, 0x42 - int 0x13 - - jnc .exit - - DebugChar('R') ; indicate INT13/F42 error - - ; - ; Issue a disk reset on error. - ; Should this be changed to Func 0xD to skip the diskette controller - ; reset? - ; - xor ax, ax ; Func 0 - int 0x13 ; INT 13 - stc ; set carry to indicate error - -.exit: - mov sp, bp ; restore SP - popad - ret - - -;-------------------------------------------------------------------------- -; Write a string with 'boot0: ' prefix to the console. -; -; Arguments: -; ES:DI pointer to a NULL terminated string. -; -; Clobber list: -; DI -; -log_string: - pusha - - push di - mov si, log_title_str - call print_string - - pop si - call print_string - - popa - - ret - - -;-------------------------------------------------------------------------- -; Write a string to the console. -; -; Arguments: -; DS:SI pointer to a NULL terminated string. -; -; Clobber list: -; AX, BX, SI -; -print_string: - mov bx, 1 ; BH=0, BL=1 (blue) - cld ; increment SI after each lodsb call -.loop: - lodsb ; load a byte from DS:SI into AL - cmp al, 0 ; Is it a NULL? - je .exit ; yes, all done - mov ah, 0xE ; INT10 Func 0xE - int 0x10 ; display byte in tty mode - jmp short .loop -.exit: - ret - - -%if DEBUG - -;-------------------------------------------------------------------------- -; Write a ASCII character to the console. -; -; Arguments: -; AL = ASCII character. -; -print_char: - pusha - mov bx, 1 ; BH=0, BL=1 (blue) - mov ah, 0x0e ; bios INT 10, Function 0xE - int 0x10 ; display byte in tty mode - popa - ret - - -;-------------------------------------------------------------------------- -; Write the 4-byte value to the console in hex. -; -; Arguments: -; EAX = Value to be displayed in hex. -; -print_hex: - pushad - mov cx, WORD 4 - bswap eax -.loop: - push ax - ror al, 4 - call print_nibble ; display upper nibble - pop ax - call print_nibble ; display lower nibble - ror eax, 8 - loop .loop - - mov al, 10 ; carriage return - call print_char - mov al, 13 - call print_char - - popad - ret - -print_nibble: - and al, 0x0f - add al, '0' - cmp al, '9' - jna .print_ascii - add al, 'A' - '9' - 1 -.print_ascii: - call print_char - ret - -getc: - pusha - mov ah, 0 - int 0x16 - popa - ret -%endif ;DEBUG - - -;-------------------------------------------------------------------------- -; NULL terminated strings. -; - -%if VERBOSE -gpt_str db 'GPT', 0 -test_str db 'test', 0 -done_str db 'done', 0 -%endif - -boot_error_str db 'error', 0 - -;-------------------------------------------------------------------------- -; Pad the rest of the 512 byte sized booter with zeroes. The last -; two bytes is the mandatory boot sector signature. -; -; If the booter code becomes too large, then nasm will complain -; that the 'times' argument is negative. - -; -; According to EFI specification, maximum boot code size is 440 bytes -; - -pad_boot: - times 428-($-$$) db 0 ; 428 = 440 - len(log_title_str) - -log_title_str: - db 10, 13, 'boot0af: ', 0 ; can be use as signature - -pad_table_and_sig: - times 510-($-$$) db 0 - dw kBootSignature - - ABSOLUTE 0xE400 - -; -; In memory variables. -; -my_lba resd 1 ; Starting LBA for read_lba function - -; END diff --git a/Utilities/BootInstall/bootsrc/boot1f32.nasm b/Utilities/BootInstall/bootsrc/boot1f32.nasm deleted file mode 100644 index 897e070a..00000000 --- a/Utilities/BootInstall/bootsrc/boot1f32.nasm +++ /dev/null @@ -1,603 +0,0 @@ -; Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. -; -; @APPLE_LICENSE_HEADER_START@ -; -; Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights -; Reserved. This file contains Original Code and/or Modifications of -; Original Code as defined in and that are subject to the Apple Public -; Source License Version 2.0 (the "License"). You may not use this file -; except in compliance with the License. Please obtain a copy of the -; License at http://www.apple.com/publicsource and read it before using -; this file. -; -; The Original Code and all software distributed under the License are -; distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER -; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -; FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the -; License for the specific language governing rights and limitations -; under the License. -; -; @APPLE_LICENSE_HEADER_END@ -; -; Partition Boot Loader: boot1f32 -; -; This program is designed to reside in sector 0 of a FAT32 partition. -; It expects that the MBR has left the drive number in DL -; and a pointer to the partition entry in SI. -; -; This version requires a BIOS with EBIOS (LBA) support. -; -; This code is written for the NASM assembler. -; nasm boot1f32.s -o boot1f32 -; -; dd if=origbs of=newbs skip=3 seek=3 bs=1 count=87 conv=notrunc -; - -; -; This version of boot1f32 tries to find a stage2 boot file in the root folder. -; -; Written by mackerintel on 2009-01-26 -; - -; -; Set to 1 to enable obscure debug messages. -; -DEBUG EQU 0 - -; -; Set to 1 to enable verbose mode. -; -VERBOSE EQU 0 - -; -; Various constants. -; -NULL EQU 0 -CR EQU 0x0D -LF EQU 0x0A - -maxSectorCount EQU 64 ; maximum sector count for readSectors -kSectorBytes EQU 512 ; sector size in bytes -kBootSignature EQU 0xAA55 ; boot sector signature - -kBoot1StackAddress EQU 0xFFF0 ; boot1 stack pointer -kBoot1LoadAddr EQU 0x7C00 ; boot1 load address -kBoot1RelocAddr EQU 0xE000 ; boot1 relocated address - -kBoot2Sectors EQU (480 * 1024 - 512) / kSectorBytes ; max size of 'boot' file in sectors -kBoot2Segment EQU 0x2000 ; boot2 load segment -kBoot2Address EQU kSectorBytes ; boot2 load address - -FATBUF EQU 0x7000 ; Just place for one sectors -DIRBUFSEG EQU 0x1000 ; Cluster sizes >64KB aren't supported - -; -; Format of fdisk partition entry. -; -; The symbol 'part_size' is automatically defined as an `EQU' -; giving the size of the structure. -; - struc part -.bootid resb 1 ; bootable or not -.head resb 1 ; starting head, sector, cylinder -.sect resb 1 ; -.cyl resb 1 ; -.type resb 1 ; partition type -.endhead resb 1 ; ending head, sector, cylinder -.endsect resb 1 ; -.endcyl resb 1 ; -.lba resd 1 ; starting lba -.sectors resd 1 ; size in sectors - endstruc - - struc direntry -.nameext resb 11 -.attr resb 1 -.nused1 resb 8 -.highclus resw 1 -.nused2 resb 4 -.lowclus resw 1 -.size resd 1 - endstruc - - -; -; Macros. -; -%macro jmpabs 1 - push WORD %1 - ret -%endmacro - -%macro DebugCharMacro 1 - pushad - mov al, %1 - call print_char - call getc - popad -%endmacro - -%macro PrintCharMacro 1 - pushad - mov al, %1 - call print_char - popad -%endmacro - -%macro PutCharMacro 1 - call print_char -%endmacro - -%macro PrintHexMacro 1 - call print_hex -%endmacro - -%macro PrintString 1 - mov si, %1 - call print_string -%endmacro - -%macro LogString 1 - mov di, %1 - call log_string -%endmacro - -%if DEBUG - %define DebugChar(x) DebugCharMacro x - %define PrintChar(x) PrintCharMacro x - %define PutChar(x) PutCharMacro - %define PrintHex(x) PrintHexMacro x -%else - %define DebugChar(x) - %define PrintChar(x) - %define PutChar(x) - %define PrintHex(x) -%endif - -;-------------------------------------------------------------------------- -; Start of text segment. - - SEGMENT .text - - ORG kBoot1LoadAddr - - jmp start - times 3-($-$$) nop - -gOEMName times 8 db 0 ;OEMNAME -gBPS dw 0 -gSPC db 0 -gReservedSectors dw 0 -gNumFats db 0 -gCrap1 times 11 db 0 -gPartLBA dd 0 -gPartSize dd 0 -gSectPerFat dd 0 -gCrap2 times 4 db 0 -gRootCluster dd 0 -gCrap3 times 16 db 0 - -gBIOSDriveNumber db 0 -gExtInfo times 25 db 0 -gFileName db "BOOT " ; Used as a magic string in boot0 - -;-------------------------------------------------------------------------- -; Boot code is loaded at 0:7C00h. -; -start: - ; - ; set up the stack to grow down from kBoot1StackSegment:kBoot1StackAddress. - ; Interrupts should be off while the stack is being manipulated. - ; - cli ; interrupts off - xor eax, eax ; zero ax - mov ss, ax ; ss <- 0 - mov sp, kBoot1StackAddress ; sp <- top of stack - sti ; reenable interrupts - - mov ds, ax ; ds <- 0 - mov es, ax ; es <- 0 - - ; - ; Initializing global variables. - ; - mov ax, word [gReservedSectors] - add eax, [si + part.lba] - mov [gPartLBA], eax ; save the current FAT LBA offset - mov [gBIOSDriveNumber], dl ; save BIOS drive number - xor eax,eax - mov al, [gNumFats] - mul dword [gSectPerFat] - mov [gSectPerFat], eax - -;-------------------------------------------------------------------------- -; Find stage2 boot file in a FAT32 Volume's root folder. -; -findRootBoot: - -%if VERBOSE - LogString(init_str) -%endif - - mov eax, [gRootCluster] - -nextdirclus: - mov edx, DIRBUFSEG<<4 - call readCluster - jc error - xor si, si - mov bl, [gSPC] - shl bx, 9 - add bx, si - -nextdirent: - mov di, gFileName - push ds - push DIRBUFSEG - pop ds - mov cl, [si] - test cl, cl - jz dserror - mov cx, 11 - repe cmpsb - jz direntfound - -falsealert: - pop ds - add cl, 21 - add si, cx - cmp si, bx - jz nextdirclus - jmp nextdirent - -direntfound: - lodsb - test al, 0x18 - jnz falsealert - push WORD [si + direntry.highclus - 12] - push WORD [si + direntry.lowclus - 12] - pop eax - pop ds - mov edx, (kBoot2Segment << 4) + kBoot2Address - -cont_read: - push edx - call readCluster - pop edx - pushf - xor ebx,ebx - mov bl, [gSPC] - shl ebx, 9 - add edx, ebx - popf - jnc cont_read - -boot2: - -%if DEBUG - DebugChar ('!') -%endif - - mov dl, [gBIOSDriveNumber] ; load BIOS drive number - jmp kBoot2Segment:kBoot2Address - -dserror: - pop ds - -error: - -%if VERBOSE - LogString(error_str) -%endif - -hang: - hlt - jmp hang - - ; readCluster - Reads cluster EAX to (EDX), updates EAX to next cluster -readCluster: - cmp eax, 0x0ffffff8 - jb do_read - stc - ret - -do_read: - push eax - xor ecx,ecx - dec eax - dec eax - mov cl, [gSPC] - push edx - mul ecx - pop edx - add eax, [gSectPerFat] - mov ecx, eax - xor ah,ah - mov al, [gSPC] - call readSectors - jc clusend - pop ecx - push cx - shr ecx, 7 - xor ax, ax - inc ax - mov edx, FATBUF - call readSectors - jc clusend - pop si - and si, 0x7f - shl si, 2 - mov eax, [FATBUF + si] - and eax, 0x0fffffff - clc - ret - -clusend: - pop eax - ret - -;-------------------------------------------------------------------------- -; readSectors - Reads more than 127 sectors using LBA addressing. -; -; Arguments: -; AX = number of 512-byte sectors to read (valid from 1-1280). -; EDX = pointer to where the sectors should be stored. -; ECX = sector offset in partition -; -; Returns: -; CF = 0 success -; 1 error -; -readSectors: - pushad - mov bx, ax - -.loop: - xor eax, eax ; EAX = 0 - mov al, bl ; assume we reached the last block. - cmp bx, maxSectorCount ; check if we really reached the last block - jb .readBlock ; yes, BX < MaxSectorCount - mov al, maxSectorCount ; no, read MaxSectorCount - -.readBlock: - call readLBA - sub bx, ax ; decrease remaning sectors with the read amount - jz .exit ; exit if no more sectors left to be loaded - add ecx, eax ; adjust LBA sector offset - shl ax, 9 ; convert sectors to bytes - add edx, eax ; adjust target memory location - jmp .loop ; read remaining sectors - -.exit: - popad - ret - -;-------------------------------------------------------------------------- -; readLBA - Read sectors from a partition using LBA addressing. -; -; Arguments: -; AL = number of 512-byte sectors to read (valid from 1-127). -; EDX = pointer to where the sectors should be stored. -; ECX = sector offset in partition -; [bios_drive_number] = drive number (0x80 + unit number) -; -; Returns: -; CF = 0 success -; 1 error -; -readLBA: - pushad ; save all registers - push es ; save ES - mov bp, sp ; save current SP - - ; - ; Convert EDX to segment:offset model and set ES:BX - ; - ; Some BIOSes do not like offset to be negative while reading - ; from hard drives. This usually leads to "boot1: error" when trying - ; to boot from hard drive, while booting normally from USB flash. - ; The routines, responsible for this are apparently different. - ; Thus we split linear address slightly differently for these - ; capricious BIOSes to make sure offset is always positive. - ; - - mov bx, dx ; save offset to BX - and bh, 0x0f ; keep low 12 bits - shr edx, 4 ; adjust linear address to segment base - xor dl, dl ; mask low 8 bits - mov es, dx ; save segment to ES - - ; - ; Create the Disk Address Packet structure for the - ; INT13/F42 (Extended Read Sectors) on the stack. - ; - - ; push DWORD 0 ; offset 12, upper 32-bit LBA - push ds ; For sake of saving memory, - push ds ; push DS register, which is 0. - - add ecx, [gPartLBA] ; offset 8, lower 32-bit LBA - push ecx - - push es ; offset 6, memory segment - - push bx ; offset 4, memory offset - - xor ah, ah ; offset 3, must be 0 - push ax ; offset 2, number of sectors - - push WORD 16 ; offset 0-1, packet size - - ; - ; INT13 Func 42 - Extended Read Sectors - ; - ; Arguments: - ; AH = 0x42 - ; [bios_drive_number] = drive number (0x80 + unit number) - ; DS:SI = pointer to Disk Address Packet - ; - ; Returns: - ; AH = return status (sucess is 0) - ; carry = 0 success - ; 1 error - ; - ; Packet offset 2 indicates the number of sectors read - ; successfully. - ; - mov dl, [gBIOSDriveNumber] ; load BIOS drive number - mov si, sp - mov ah, 0x42 - int 0x13 - - jc error - - ; - ; Issue a disk reset on error. - ; Should this be changed to Func 0xD to skip the diskette controller - ; reset? - ; -; xor ax, ax ; Func 0 -; int 0x13 ; INT 13 -; stc ; set carry to indicate error - -.exit: - mov sp, bp ; restore SP - pop es ; restore ES - popad - ret - -%if VERBOSE - -;-------------------------------------------------------------------------- -; Write a string with 'boot1: ' prefix to the console. -; -; Arguments: -; ES:DI pointer to a NULL terminated string. -; -; Clobber list: -; DI -; -log_string: - pushad - - push di - mov si, log_title_str - call print_string - - pop si - call print_string - - popad - - ret - -;------------------------------------------------------------------------- -; Write a string to the console. -; -; Arguments: -; DS:SI pointer to a NULL terminated string. -; -; Clobber list: -; AX, BX, SI -; -print_string: - mov bx, 1 ; BH=0, BL=1 (blue) - -.loop: - lodsb ; load a byte from DS:SI into AL - cmp al, 0 ; Is it a NULL? - je .exit ; yes, all done - mov ah, 0xE ; INT10 Func 0xE - int 0x10 ; display byte in tty mode - jmp .loop - -.exit: - ret - -%endif ; VERBOSE - -%if DEBUG - -;-------------------------------------------------------------------------- -; Write the 4-byte value to the console in hex. -; -; Arguments: -; EAX = Value to be displayed in hex. -; -print_hex: - pushad - mov cx, WORD 4 - bswap eax -.loop: - push ax - ror al, 4 - call print_nibble ; display upper nibble - pop ax - call print_nibble ; display lower nibble - ror eax, 8 - loop .loop - - popad - ret - -print_nibble: - and al, 0x0f - add al, '0' - cmp al, '9' - jna .print_ascii - add al, 'A' - '9' - 1 -.print_ascii: - call print_char - ret - -;-------------------------------------------------------------------------- -; getc - wait for a key press -; -getc: - pushad - mov ah, 0 - int 0x16 - popad - ret - -;-------------------------------------------------------------------------- -; Write a ASCII character to the console. -; -; Arguments: -; AL = ASCII character. -; -print_char: - pushad - mov bx, 1 ; BH=0, BL=1 (blue) - mov ah, 0x0e ; bios INT 10, Function 0xE - int 0x10 ; display byte in tty mode - popad - ret - -%endif ; DEBUG - -;-------------------------------------------------------------------------- -; Static data. -; - -%if VERBOSE -log_title_str db CR, LF, 'b1f: ', NULL -init_str db 'init', NULL -error_str db 'error', NULL -%endif - -;-------------------------------------------------------------------------- -; Pad the rest of the 512 byte sized sector with zeroes. The last -; two bytes is the mandatory boot sector signature. -; -; If the booter code becomes too large, then nasm will complain -; that the 'times' argument is negative. - -pad_table_and_sig: - times 510-($-$$) db 0 - dw kBootSignature - - ABSOLUTE kBoot1LoadAddr + kSectorBytes - -; END diff --git a/Utilities/Duet/EfiLdrImage b/Utilities/Duet/EfiLdrImage deleted file mode 100755 index 2e0a89f21eb92201cbe12108992135dbda61eaf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35268 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 diff --git a/Utilities/Duet/GenPage b/Utilities/Duet/GenPage deleted file mode 100755 index 070ed4e6515dd41c720b2c1fbf0059e0cf56706b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39476 zcmeHw3w)Ht)%R?YB^QWKQ1H^X)<*?Q6fi-eM2XEp7M_(2L;`{rTmspJ)Fd1BLcmL1 z+(h!QZcV+n)i%}}ZEfFJFJM&M5KMwt4N5Css?mDc7%%aL0fhbjXJ+=2CA9tC-}io( z-^c3C%$alM%*>fHXJ*dKhF1=Jb~v3eLn>pw6vmi>Z^M)PHCv#oS{T-9}}V({?s@JW76 zqzL#BoXBrjTY)1rbVU%4D^AE zEJx-=^+m#@C(z*pJ*lg)x!2dOaMsxBJub9!WPVY0q;FI{`l0bWGYTNK*;YB@qd@R* zemN*l?K@ePAvl@e#9{nuD*svga-;lsr!jYu_)&jzhw-bb^i;+(lG|6ZMzk+Sk`SEO zzIaKIve{O+s5oI7=jyU>R?PDw-3VY8@jD?{Tq`Q2K zH}N8D^6e-CrlXNxE(;NV`Yy%ya(vIi_o$!S7@Ic&@;KzF_>RH%T(8@8ZcX)ybF0?Z zQ~{>Xf8a~)xT;M3)frcwpK;r*qfEzF|KrRF$m3%?CX2D`EOvGjMob^*jE~BdoW#Lc zK=sVPmvGca#y)`f4e`2Bf5m#Y$6h;i)>O2kdIcw9lMqpTK3&KoPr?lHIrcdwfnyRl zCV^uTI3|H(5;!J-V-h$ffnyT*|62l!HT^>^SZpkVizZlj0wQbBI1W+4t54Ipqad`b z|M!=`4|Q527nG!bXaQr(`tJt9!9P>G>)8Ezn-5J}4 z;KK;-wlEejmR-$Qu$fLQ{`bDu{5w-MeKcS-0S*xMX*zv5G^MWJp|}raJUt4BA&25L z{sm_>#Myrp@%X=s_|y+YJn=J%@rkt$#NRrUJ%fl3Ih29@_9@V;fao82NBNPh2o!T{*DZ7!~Rh?fqEZBgYy#`oPh?T{1hK5f0{`C`|8ILnb%*E zSbvVJKZn;3lK;N?v#5R}owWUZ7{4BjpZ{c8{rwpJt)oEk@5sNC%fIuV%D?Iwq8F5#?*p}- zHUZuE9J2!5xCq?0A(OSIlu$2Fahcv9etrsZ`!4+S9L{xMDM~ymO1z9Hsf0y;BOF8t z)3XtL`dk0Z5r-D4K`j_FwAWX{KA3j5r_U;Z8F1Ug*bHN8Bm+!(S5;55hUXK>Ip@&!;k6glT zH}h_X+Yy)QeHhY{uQXj{T4uW1WLpNcIIWbiBgWUF?=$HUn79ixSe--XqhJ1r!FvL7 z`XJ@-Yhd;a4cEYRmcZ2+82y7FBxQI381(QmWDUryKZ~r{$a+_1{YGRh0M``dmT$qy z6nVws@5(3$X}Y<`8l3n%D6PRM&miJ?p;GM|Gp0Y2J+2L5Wld>o9Y|lxeIvZt;6_iZ}L1_v6G()3#`8F!?{dkJf z_!<%g`?TQV-tY%M=K8BNzd|htl=WKt`?Fl@`-vpcUd5Q~21m}M2MNjKH&G_1qg24$ zs~c}vf>AjyR_GMu^FkzAS?DLxLKCBftSIE~JPf7D!BTl^(cwsBz#G{`Noa@Na_DE*n!hOpm5-1Cq*R#JOF<-3~*K+WBtGUo|A+G$yrp{TPV^dU<<*! z0C!>dz@i6H%!Us<1H?u_SVDxq1>7LuCPV|b0bV8Gm4v?u@Dc&90o?C|^+Q&v$ZAAZ zV)L%a1_oaFYwD0y7 z?BvrqzF$#t(vDMdtjFajW78C6tX0Xu)v8o7_E^a=wJ153R%L8Si!xSg1>6QW1h@@w2yidpKESd%Qq-$7-iW4K4P914w>59OH8?Ax>AN-md+DB&weQ|=v}lnRm8V8&k*?-+ zEz+$;I=r7*{6p!kdCF-%lw?3Qrz=m*F*MILAWCVTn}R5{d2TAAwC1^Kh>Xp1jfh4y z&mE=tw+|tit_9a-G|xqJV}|!x*!tLhECSPWCWIsIp?x5ncFj8)K+fC@Wsb(*m_-V(f44z*7Spx=f;z^z|vWQ=Fi9^t;H_P zvu4xi#+{yPu(<4om7zsCR7{hN_FtY0682qxK{nRza?Jbgs69#pyMmBK-y3e203F6Q zYz?ReegK-AqcoVrlBR;wg!#TPzR93cH=vY%DB`KmyEXlW-tdjQ38T1i-bm%;CeOm# z;5AtS7xN7e3}`QHohBmRgzcUl(k?RhdQT^wAJ3$E2Y!yWOpmq&Hi-4l6UHkgni=oJ zpU)JXcoaoZMR*Uz-J?*5_0L8rV%tJ_{ujRKpN5Rs{z%h@mUYVcI9&cF{jb;zll-^Q zmIxmoKfT?BR9VvpN@Ea-O{tAohWtoj93Ftlq;Z%*HHmRJ+pK@aJB(ecRsV##Tn?-r zvKEECdDN`^7tx+?-@q(%*B-UGanbKR1H*C#aI2y?YK$1VXMrOYPk{y2wiB%SVA2o` z-wz4Cj*fm~qyy$F)pI48FXf9+!K(;&Vl&x@IvM*~ zagI9)!Br>aIF#?V;im``%EV>R8sv zd4`BDY~ga(Rhr(RxC@{u4qNDq7A`MK=^$xzHb0<^&+?yr=st_!562} z?{RAV{va}E4I;<_(1q_Sn*S3RY8dJN1k~YB>U-uR(St&4Qj&fPf~5ILHuhi2@AChG{Lba_Gjv0QBg=0j>0O;5JqL;I{|Whdp?^71 z{Tt-^H^}ubP3qsWqswmzI(gL+4Ba8<-yzb!9HD>bMfES3HdoGPM=BQWP>L3L+4~J? z;CF8*Taq;}-}RH243}WDfKO~a9a)}-ppS=!>Ej{j<00tdA?V|wM14F2eLNJ^#}Mh` zp{PC{is~cf%rHRDf7-znuZR?HAt@d|pOe1*OL_g1`Fd1&iTN5FH5*k2=vupOtJF5fcu zrjr>C&o~t{{LGBfzNm90zDOqO)3Egg{+3*e{#8O*w12Yyz=VcNP}|)lyf#BpZ7=?i zTGW}^|0HSyS-l{;4pCyG9spTC`6?QBmIl&GAr6QH8%W)}m83!kCB&I@CP$owxR+!> z^0AS88c04jl6+Pvo@}%fu7K>{p^|~o5*S5m@LSx;qIGY_XhgX9torLQ`7Mrkdn4YS zh&L4RZVi7koy)RZNGLbaR}q_Ue0|#RX$u;z1)r=3)9^`!NaHlAZP-ECv|WnNPcF~P zDlGb8)2304AUfDJj{u%0Ro*hx1O4TBrjUn#<7Rf73SJRr${UgD-zfrb? z^!@&hKL5}U9LnrhxYqOiLCL;ugZDhFY8aUbG!aj8_eVyKfM^(0Ndc;I+i&Jy_fyHk`c>HeWi&o@wd|B&kW6g08<2OE)s zONkW!P`>ADOE(FFfj+49DqD8?_h&ZDF&DgLY5&Vh;?tsR>DhWNXtcZ@%XjZ<9iOCH zie77&F)x_*D{Js7Q*W7mN|dGE;qMS!vRv@0?1NR&FGg<%PO(IK2F6iJK{hHSTjGK1 z9IiVt!0%(fj9FC0qwEuLU}*m{jo@ARlwaH_&}M+0Ipoub z$s3m@Vu0^LSq$(3vLhCQ_v3<{d_KhRE0XXez!PbJ$Br<*3Py^?_YMC+jITA=km5g> z?;QtyG$~t-!#N?vzn{i8_|wC|%YTE#p)+`SpGg=$Y>;;O_b>I1$C7cF$P}#`y})Yn zDFPT;37QLDwQQx4!bh<@4NJl3J8;sl_E-!Dtord(BWk`lxB!dHmN!iPgIVtJ8lZs- zh&n+Y!3EEAMVr{L-l9CP)9nr}fN|a#wDtM-lWBezt;5ECr`FM*W-aKj6usDRp{3*f zG_cHUI3AkYJ8;WzepFmP=BNf4z~wD-zLxx3-sAk`V2zv6==6W zZxrY=34JD^p9Y%iUvMt;4^uU(&EPsIDxguWG5&7!4SG3BxeaT1+}`Lz{*Wk<*^mhe zY=C>0b&6FkxFBJT17asv=eRy{d+7f(2TtLkf_>p)as&pzg^bJ^SK580B<`n!TmhS{yQRJ!JnMWCHR6s zR|#}Ap}7UW3+UncL+f;!7D$h-zmvFB3(poMb7^RrNw`;`B&}yepRVZ_BrMsdh$7!z zKviddOO@SDMe>wQ8698b2+S)TeL0yugckb;+N@TH$6mGR4FPYz$54_o!G!u`m_G3c$>CN;Y57m7xuh(^&<+xA}S^mG(RoKK`5!q|<9 z8oM9z1dQD@N^Cf6q6N!e3ZP_P7goK?DI0!<-C=B&l#SH@X+O2k^JB}_sMUzA?=TNz z=9+?*=t6OV$=~rjOb6DUi4DiWB=op5;O)gR$+f3oC!)A@)s)f>?;2uUQxGys`#DG1 zlC}T`%jnXR*^q7Wg?df*L-Yw8g0!>i+6hdzi=sydzL!e(I^m&B7N1$&P=(z&@JfVvSyEokIqiq>TJq<0v z@V*;;Jldc+UcD`TSpCxJ+3{Z zy^pqPBG_~CGl=}uL_(DGygracn|Tmn=3>5gU{YdF$tPDg-^Ld@c$6JNBo>EzCUIeI z7U;PGZ6!2c9M%hTCLOMVg}DNqN<%?!P{LOT^e21_3Nr;dLIasj=!<}s`}Yy;>o2JI z5%yI_?uhpFubhA3Zwsg~*{#$_ZeRCIJkq}MVQ%MRL#KvUkV+WlK)M4*#nYsH8) zLjf{_*9!Z4D?mB6dGNdr*DsX6jK+7N!He_5I;J>^dT5e}A(i9Fs|P!5 z3!{jl9#0sZ4q;j+jM`Y<)xtKu$R?R&Y5q9${bYRfA!&YKd(hO(9t}6Z9sMfdsNEf3 z5BqdsXmh1k3 z85)k14a=L&ug40V>&+XH+Vp%HRd!P~w%-Gzs1dH*fH`E+&E)RcN)8d@rn1+YGqgZi zn+BtSjg}dMX2A0pD}U}XBf*6Pm9lefD7=_&%Cl!9YQLP6qW%o7adQOvG=YAA&{q@s zQh`28pqW6Q4XE8l=xIO?*QdnsT1p3^fU%YgdH|BgiorKMdsDdcMQQvT2@J?R7?2iC zU);)%g+s_Jc+2!`4g`>}feCusupDiUZ;J{d13$uPC&i+_9M2r4-xmGvu$IRKFUN-I zEgY*{V}qAJ&yy1y=3%?E*KHn#S8m#bI{h8H`KIRrW#cZcVmrMntoi^PMM~4%q+w*j z{RhXEY%#d*>!-&WocuziX+6>i!TBkC@9;e73YxCJ z-QR#g)}CSPdt`mjH06O^ioYDCAhE5S-y+V>-i*B~-^uO?-#^H86qP8=J|ZPG(0in9{Yyv6XpY@iDT#lM{sF5cYiIW^S0s4#>jJ_UP91A2nIS6XVA3-M%fNMdd|0WP9TQdFok+p%k;_pg>?)Cox`6y)Z zf1l&Ujr_qJufs}HF6a$e1GTMI{R`9){;5ixf43~}*mGvr3 zy=W9pW=j*M0op|aNlh#5zk-A=m5R;;&d;I}U5BGfS(~-!OA@2!5j^t++(de>!JnAK)(dQq+*cLhBG4%UeVIVtOQo9#-7L`mfVd&u z3j}(Agl{KwwLtF>=#vHd3qt>d(3c4GLjt{@?_;w+BlI8zLwCR{SZQrzDE?}^){4k-*)V8z9KEAooz;Rh<-$g=s_}{=VDyvAfap_ zQF?x84bH*9(RmExwFKjJiS(Pv@%qv|iw1_q>k^FDE3Sob&$=?T;28L6Uv!lclauJ8 z%YoxN#s_>kgkk#3(Tx_%fqGK(XW%RnY4(3mf1alPoQnQH&+iiGmjrq%p|=tG@PBZ0 zgFydLpw|$(mC)}B^iqNTnLy8?NpwG7n1%HY|#}!;x)CH3%8v2N!e~9S&sj4@AAnDUENutD`iFREph}RME*F^j%h@<|F z#P-SgMSg7fJA2@-^qxE-KHu|=zefd0LCC*Ycx*w?6-`tv_iU#y&1WJCbub{>e0=ETF{(> zINWXi0Q*GNZSI4?gF!I&Y5d)K@%eyD^*74&-Qi7y2^iFhsurd%El`conxMxPg8O zJCaCtJ`rVK%)^rr4m5{1o;1RFD87H)@M$jg;1J+e_<5~*QwWhBd3Hw z1+?J!2SI^`pM;WH@Ht}I9sxOBB3_5QF7qqQOy`}e$@;_cqLelGB-OeNm9Tb3J80~h zzBB9L@UKoJEa!qt&hT_F;M}yl?N1Y-xcLnGK-Qm4wFIAQ11F+YK}+!t;K;;Xh&|S3 zS{egI?KLnwspaDWT27>+G*B|8G@xY!PA(0Ur=cIKVWA2_^hBV7io!q6e-^O^jq7T9 zm4xKz=EAyAO=#LLKs!>?J{*r1VAS6`P#*m~2i%X|-#>slfobVcn6`jyU=BtAKC?nH z@rjZSk3%UEGjPptLeOtHzCZ!2fG2D+7J+)YVY9)L-esJOw1FCfPSGy%ub_H{1}oYT za99TpQqw6Qp>fOtc=RKbV ziHGmx0G|eQ(wu4ym~&){@QPCC(0Ac^oQin-mh+&K^kSZ8tl>2?{(|v%OmCW33ET4U z;S(?;VDHHuS7;kP4Wm{I{nX|w{UAmt52mi1+qj^xcy|hmw+t4~4vSX{i|2*KyCHfAfa{L~#vG(z`?AL%RvPa^t%336qcpq-PtVOk zz_5RSnfE8Ke}sVjLtpyuA=2!>B1u;0FVwwYlgg`vl@s=FZ?}1muz$TLgIo&~J_)+O z_${0oFE)fR%sUgW9bpS`8T>~0IvR|Cai(nUMdm?oHRKgWdHfzJF#Z~p#aL}B+P(H> zU-4srnD><~<7Olbk?s2Uc}PTzms1FPD7QDaqJ~6!`0#!-G+QO2?5RA=Ksc~5+;IE| z_VB-DJg$UJ$HwDk^cLe`4j6q%k*WM07cXsd0^{ouit+dba(%_m0%qR&F5}~bh!~e5 ziWnUT`^mxvvS(8UMumKo|IVnK2D-rb(>Zl)RDN-K!l--*fnii0hFVjjX;hpEqmsQF zy$Ou}2SSWZBgV$(D;^Ji%)7J8I0gwc^D$s)gr1`qV{<2BOzy8yPvY2Q;g=MV>_#HW zzKw@92nRNV-@^G=+^;3>2lU3`k@R|#@ml~G5Un(j{W+3w zn=6fXlWdDW1{g5@9id^U6!%p(-;8WuaW2}(yjOP_PeTHo-2sA#@l}NVKj-EClQOVV zcmy%VRx-hulNo?%===O zF@OZxl#hr6KNGPDOO~E}JW?2fdeo6P1RM9!5EzI&Tj60psvYo!m*O{qv>lG`=lK3H zaXd`4b^R~x&MardhoflxHK?(n_@3yaBymmuj*IJCD3?&!A#Y|(T;Z1E z(2v-8Q`3u2MQwWFX$VKS@236uL3&efr6pz`%EG}k&4pDnJA^v%;%^sKjolVpFrd)B zMcu*T_t2kqxV3SHcqiP2QeDQw$fCUf{j?ILZxW@qQE9$gLwSzuH-bg1eachDohWF) zkwoafUR(w^cK=KEiTsHc{Qz`!1}zm>4zVj<&Z9f)d32wTM-R2|=#Q;Dda{j2&xH`t z%E6g4m9*}6?45tg!k7Ogr4rO6j zsrL|Rc9KnfG|aWcU!j6J`=9ta3eLbXs@Qfp((TQ4laau3%jg&_@Ti|)}r^U z%AEJGced)ElMneq(9ZT{66jokzKYOzP{YEXz&0elH`wrL2DfSS^CpbuIpk5}^Qun^ zq@wvs(jZ>wN~sI~F?|A$Ti zgJ9t-9%U~?)c#wLhSShXi122CK2xAILO($057Rk%l|ZKn^bA5jNa!wsCVDXc5SwbO zB6A4+5TUt$?+MVv`$y|@Oh2(s%s?y4^e&73I{kz{VBAB)AkOabXXY0F4Rjiy=cq_# zAW6Pe?mVZ9MhgxJD_uZh+utN!FxL@j*0z=hUSA3ZK3MYtbawiP3w z)wdM=m%qd{o8VGM9%PjVS%u3uivRen2tWC~(z6W1tp%Q>>chtai4i|j3-Fd&ieBQ4+|(a*;X1eIke(#u7)_Zl!4vorD7SQI7`3X!@=JTu$Cc z9f8c3)9~?KH123+!b&X-#vUDm*J)cKjJcZ>;(zQT z{`*Egn)KF-uVpilpgH{>7)2ik|%p>oMP$tAWi?;*V*ekn7Q^jO8v%n(AaPSG5g)& z(7n9UsJ(1F@-HfUGC$kvxV$%CzbZ@((uB~s;jgz9~YM-u8WWMbIf@AxIYNvfJ4;~ zY@KHjokQxj$yH0!w}-=gEJB{CuyT{(MIsw`HQGVcw8C#Ylk^&y=g7=-WG22r;x~?) zsARD4HuyiFSV2JTm7otVBJRQBYXsUY(Bvg)UqR?XplL;o&DYp^gTEHD;Zt&qi61D# zKvZ*27@A_<%XNpQ9$%(kLIUql=m16SG=V1!@mjfH<1d0NMt$=4AVe?-dJrt+QXmVC zgTedMN%T0E8^n*oS4pYFBtZ5rFCmlD?F&zrS&x{uKwZ%aG&Dq=<@R~6cOeW+H;gm& zgp70aeV><0qHx7nF0W-IkYABNa9SpLT_(`81^Pim?e`KI29T&%>Yc(8t4@c-Y9pn|avGLmJV@#9MgyGak0^@HQUa!Na?F zcn=SM$-{ej_-h`v^6>ZU)TfksfKu;M>M2U?rPK?QdYMvtD7Ax9 z|DaSmrM{w68>Ld9GW`!zYAmJhrIbpk+mJ#p_@`u8?3Yk9#u_YhqH##V(U=}1@J}=@ z5uhsLCxj4Dvu|+)ywQIceS%lome$>VwF14oyF$b>&h!v*;%Q5t-Z#HKP0ct z@>bVWsVgeo_9_*m3+-#Gsmz7y;<{_nj*t-aRiTCc9GtgCZ+)D?EM zvZltlveIL(I-NC~vw~Ub)>hV3SE==tuF6`w2fUs29oQ=NP38S3c2&vhK7P~Rd z7phW&r`p%q)horwxtFPCN43>iS!H)wYC$z0`ln`P&34wWcU7-i4TV^lr%ubypP^1c zR4{$AYJtdW)Y(o~y%TbWl1^1sQ%#M^$=xbO((YOd5oBel>S9lIO|@se>T#;8>~(g~ z+qvGw>Qt+#QWgK4f~T^&j6)!f?Zy1b)u zo1zwhqH-NkOj%27wYyxHy;72HwV@gVy~2Lf=2ca@>uW04+pDM^H`U{Y{Xu(TpJ+YKx*DhjOi-+{ zi;^16TR5!B(y@EWvVdSOr@m@%@q~YzNldwhBzw6MZ-9% zd`ZECB-Rdf!JIi2=0&{I!nBKwf6mP5uBIuC{#AN-C*utkgI`%+Z?AM=s0e#hUQ)~? zH)_ljx5F9JfM^1XBR3R$eQauart_(`M->&H=%7z)1f zB$aF!iE~0zCF=$kWFYHJ#2&FoGd|bmdaJ7zIcIqt4!bKi4{Ll)4fX>K)zFekb^c~uNF>Ls z!sDv5+UqLVZ2nJySgTh|UCDBD7hC2pnxCfvOQM*h=C8{apMpHKxLD1{4gf1}U1beS zKi|oeJDoMGOzd+`FIIDN*E+GGIXf>ukE%co6cMi@k)>EQYb$FOITyopoj<*T<&H?2 z$8t;YFaKrX0x7gSkpvRWY8s-B~wxigESFmH-xUl*@wA=GFwdQrWq&R%u?bS8!| zsS36P8evZ)OYS@^ms|j73gvu) zoR<2v(@kQ##&Tt1r207J`B6$4Tk5Lp>u5~WnQAWWNu3Tg%4EvLM3kqV%hi|=Nti41 zm*wSQ_ft&^6WX`PX>zZuuBJXEs4L%YkEE`-rFJ)FHD3{rXmD@GT3B#Cq;a-v_e@Mrs6370?E3Wy@<{CTk$M%I!|_JWcY?>iYNx0lb35A7;SFU` zlW>LI<>a$s`1~n29|xm^X$RQ6aN&Z5Y>8>%e9Qc~jPHqH$);D4*%EGpsaXu@>0V?`bTgHo*04_1RO5t2iy7av?Po1n$B&gbn%6&o^Qo!s%x>G5;fVYc-O7fb#_*cMapie zbHLp4O}v=jB0UES-IR+dfFVaQuU09?lZ7HV=vG1=I||}dd52WnL=?=5XGHAD-A7P|Mq$o>$#;4 zI%cn|jdvrly)i7#Ep&Lt4H^IU!=@vq55@2n(8sWQsnK9y21BJG)o?mXF^nCZW}tst z&I%-bpT3I7L^>7m7uk5Q%sI1@{4o5c+E8cR_vjC^VT_UGPZ zLPihExJ}0GGTtHMmu0+H#_!AcQyK4*F}qsu%aZXp8UIMexiX$69-S_N5R7vQ~3(Hb+5$ZHa=Ss(T~|k0+IFm0+E0$z}>`+<-+ix_nJJR6_W^be~VcnVh){lio^M@5>?p1Kh z%_om!4W(ZmGta)B5_`swbCZ2JW>q;Z_xalu_Cz*Isaoo2(OrZxlY>$B+a}c+lF{x}2Ub_@}DZus{M!a6wFglgBPQ=fmp*$YDr3(I5 zJZdO|iy3bHSS#GDEyc;6Os%Y0>8$}B`&n8l3!zv_-K=Wybf_!E!`@3xWqoHOx3ap9 zeVh`zb(`a@sVOHpy_=0FL&(#tC|^(I;MbX`??M!ye?=uF?sJZ$O7C|C zW`ftv{y?HC23=nXg256H&t7d`d5zm!%kEFBK=@c1OPRqQO@l+f1AXtE1(F%;S%SL& zx0q3`cP;|oCBX2?-$^SIuQXT}3E66h-lVe6i9;FHv;aXXUel#WCq28}=*A@*oXG6H z(JX!T>PlP&EylgHi+y8^-aW8=qo7%dcayiK$FDiqcj*>4do%-VWN`?#js-KzFai|~ zmG%7o4io>)Ec6$3r=hZ6j*24KP$q5{=mw3okH!Y@G(vz+;*{`XZ zMNal{2Hn1~doz)~FKagI%anT?(^9OTf}|Wut5;QfNXnHfamm8oCuvlU zjB7?w-{mMO8-E}}+@s!;MZEo)>~0XWUXJQ~S0iYn06t&TZX?h}C8L+Q?5RwC&C)l9 zrC=bpXF?0_MsM4egKF4)E_**yT-dM!m{FkpoM?Xz+P>w)yAm@W8G6=v)7a0lfd4DR zKUfKrZv}!@3R+fzh->r{S-2x*?`HAaN%jPBaS-WGD5yo<7}(w{x~01rxWQUvhw6#L z8sK7gtKVhCE>FLw!CpfYUIeYzBj~-6r7@r1fUu2+eLQSwq@2D+g8_~F)95tT+e8_m zn<@0+9Vd`H?A?T$l~iGGKOenB_WqmExbZ5NFF@GMV^IF*ybRubrm;c%i8OHe6@{UD zQ9dQ%a*RDRrkre(l|6=HeLy3;kBI2y8rwdG?!esaO&|x64L-l7u(g$Q`z&3Yt(=ugOK{XLZ({1b(}f9Bktq_AZRHGy6aMsK2D z%N8&HEOlh)*c&JudY?#l@GwLVR&h@=Azy7Z_NDe^NDi$FV9iydsACeeW~@mDdpvDsV(Vkscorvk5FD; zU$T5K#h2caO8q9?{&x~?!*3@Eep14%67G<& zI!WMPl5nqt-<5E=S>QjDaJ_8bK?(b?JQ06ms%U@T6#_mf3Y!F+D`7lg;PgdNyp*3s z!h^CuOC`Kq@?RZ=C4QZReX|9>nU%-LgD^}4zbxT4lYsjqj5~CW|4PF7(!LywmOo42GmIp^ z9B>lw4++k~{8=Ml`orM_mr8gZ!DAQ;N!Z5AgC6($)E>KpRVlw(z{n>Q|7=KtZ%u;f zuU;q8KavDLodmy>1izjHf0P7&nFJfKUL@9+nFK3I@QF$AsY&ppBzQ^^JUt1fpI|1| zZ%Tr-BzQ>@On;F!vAiP*UXui`Pl7ij!Fm#WYZ82S68u0C{D&m?@g(?}B)BsPeklpw zlLWt=1izmI!%Q+PeT<&3;AsY1j&CKtEAU;3Zxz0Fd>#0%!gn>k)%gAd-)r!#!53Ri zR)?<>-+FwZ>db|&8(&)Qz4)%hw*lXE_^!wIT70j=_j-J9!1t&4-iR+gCD=;P^ALtj zHv7M+eP|A|MNfUP6H+XPA82Aw>?CB1J|0XwE7@j8&+gHKEw=qfX3j{+!?AZ54PZh$ zsGY#u`-9rR=Q@$-KC z{5k@1*n!q&iTW07(&1zq=EbtbT~apwg3l#KNC1f^D2b0AuWaS^YLYJ30HmXCG8;cR z2@Q!QV{Q9q9qJ#l4e>hv0aQJn>upDuN!L!8u1y9DW5dcOn5Re>pbr8KY z5Z49rqCj2|#O?-=pi2QBxe>YO8h|1@LhkrSl<4udIk>Ce<`6#q1m}L#t8c3n?)<19 z--a5%T6*ree_p!mqrQ3`(?o$Z$^A}o4XHC??vJMg{^uFwffug#BQA1Wl~t|_&po&B P{DSF))2Gn_h|m83xWNjp