Dietmar Posted May 20 Posted May 20 (edited) On the Asrock z370 k6 board with 8700k cpu it works to full from Sata AHCI via NTLDR. All CSM is disabled on this board. In ´boot.ini you have to set this, because XP SP3 sits on the second partition and the wrapper.efi on the first Dietmar PS: USB3 boot works there also. NVME boot works there also, waooh, 6 sec boottime of XP SP3 to full desktop. [boot loader] timeout=30 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(2)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /noguiboot Edited May 20 by Dietmar 1
reboot12 Posted May 20 Posted May 20 (edited) WinXP 32-bit also works on UEFI32 if use CSMWrap e820 ia32 version https://github.com/FlyGoat/csmwrap/issues/22#issuecomment-2895690281 Edited May 20 by reboot12
Dietmar Posted May 20 Posted May 20 (edited) Tutorial: Building and Patching csmwrapper.efi to Add INT 13h Disk Services This guide walks you through setting up an EDK II build environment, compiling the original csmwrapper.efi source, and integrating an INT 13h hook so that SeaBIOS can recognize SATA, USB, and NVMe boot devices. —-------------------------------------- 1. Prerequisites • Host OS: Linux (Ubuntu 20.04 or later) or WSL • Packages: git, build-essential (GCC, Make), uuid-dev, iasl, python3, python3-distutils, bzip2, libssl-dev, libncurses5-dev, nasm (optional) On Ubuntu: sudo apt update sudo apt install git build-essential uuid-dev iasl python3 python3-distutils bzip2 libssl-dev libncurses5-dev nasm —-------------------------------------- 2. Obtain EDK II Base Clone the repo: git clone https://github.com/tianocore/edk2.git cd edk2 git checkout edk2-stable202203 Initialize build environment: source edksetup.sh Verify environment: echo $EDK_TOOLS_PATH echo $CONF_PATH —-------------------------------------- 3. Prepare the csmwrapper Sources Copy csmwrap-1.1.0 into edk2/CSMWrap Ensure it contains: CsmWrapper.inf Platform .dsc including this package Source files (.c, .h, optional .asm) Build scripts/Makefile Directory structure example: edk2/ └── CSMWrap/ ├── CsmWrapper.inf ├── Platform.dsc ├── x86thunk.c └── ... —-------------------------------------- 4. Configure INF and DSC – In CsmWrapper.inf: • Add x86thunk.c to Sources • Add dependencies under LibraryClasses: UefiDriverEntryPoint UefiBootServicesTableLib DebugLib CpuIoLib BaseLib LegacyBiosPlatformLib LegacyBiosThunkLib – In your Platform .dsc under Components: COMPONENTS = CSMWrap/CsmWrapper.inf —-------------------------------------- 5. Patch x86thunk.c to Hook INT 13h In Legacy16Init(...), after the null-handler registration loop, insert: // Hook INT 13h for disk services Status = Private->Cpu->RegisterInterruptHandler( Private->Cpu, 0x13, LegacyBiosDiskInterruptHandler ); if (EFI_ERROR(Status) && Status != EFI_ALREADY_STARTED) { return Status; } At the top of the file, declare: VOID EFIAPI LegacyBiosDiskInterruptHandler( IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext ); And add a stub to prevent build errors: VOID EFIAPI LegacyBiosDiskInterruptHandler( IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext ) { // TODO: implement INT 13h dispatch return; } —-------------------------------------- 6. Implement the Disk Handler Inside LegacyBiosDiskInterruptHandler: Save registers from SystemContext.SystemContextX86 Extract AH (RegEax >> 8) to determine function If AH < 0x41, call legacy I/O via Block I/O thunk If 0x41 ≤ AH ≤ 0x48, set up Disk Parameter Packet (DPP) at ES:SI and handle extended calls Set CF/ZF and registers in SystemContext per BIOS spec Tip: Consult EDK II’s LegacyBiosDxe/Int13Handler for reference. —-------------------------------------- 7. Build with EDK II From edk2 root: source edksetup.sh build -a IA32 -p CSMWrap/Platform.dsc -b DEBUG Result: csmwrapper.efi in Build/DEBUG_IA32/CSMWrap/Application/. —-------------------------------------- 8. Test in SeaBIOS Copy the new csmwrapper.efi to your firmware’s CSM path. Boot and verify that SeaBIOS now lists SATA/USB/NVMe devices. Use DEBUG((DEBUG_INFO, ...)) in your handler for logging. —-------------------------------------- 9. Next Steps • Complete full dispatch in the handler (reset, status, etc.) • Validate large-drive support via functions 0x48 (get parameters) and 0x42 (extended read) • Consider upstreaming your patch to the CSM wrapper project Edited May 20 by Dietmar 2
Dietmar Posted May 20 Posted May 20 (edited) Re: Missing INT 13h in csmwrapper.efi When you inspect your x86thunk.c, you’ll find this loop around line 312: for (Vector = 0x20, Count = 0; Vector < 0x100; Vector++) { Status = Private->Cpu->RegisterInterruptHandler( Private->Cpu, Vector, LegacyBiosNullInterruptHandler ); … } That only hooks vectors 0x20–0xFF. INT 13h is vector 0x13 (decimal 19), so it never gets handled. As a result, all BIOS disk calls (legacy AH<0x41 and extended AH = 0x41–0x48) fall through to the null handler—hence “No boot device found.” Patch to hook INT 13h Insert this immediately after the null-handler loop in Legacy16Init(): // … existing null-handler registration for vectors 0x20–0xFF … // Hook INT 13h so BIOS disk services reach our real-mode thunk Status = Private->Cpu->RegisterInterruptHandler( Private->Cpu, 0x13, // BIOS Disk Services LegacyBiosDiskInterruptHandler // implement this! ); ASSERT_EFI_ERROR_OR(Status, EFI_ALREADY_STARTED); Next steps Declare the handler prototype near the top of x86thunk.c: VOID EFIAPI LegacyBiosDiskInterruptHandler( IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext ); Add a stub implementation to avoid build errors: VOID EFIAPI LegacyBiosDiskInterruptHandler( IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext ) { // TODO: // 1) Save/restore registers from SystemContext.SystemContextX86 // 2) Decode AH: legacy (AH<0x41) vs. extended (0x41–0x48) // 3) Build/locate Disk Parameter Packet (ES:SI) for extended calls // 4) Call your 16→32→64 UEFI Block I/O thunk // 5) Set CF/ZF/EAX/etc. per BIOS spec and return (IRET) return; }Implement full dispatch by referencing EDK II’s LegacyBiosDxe/Int13Handler: AH = 0x00…0x01 (reset/status) AH = 0x02 (read sectors) AH = 0x41 (install extensions) AH = 0x42 (extended read) AH = 0x48 (get drive parameters) Once your handler is hooked and fully implemented, SeaBIOS will enumerate SATA, USB and NVMe devices normally. Edited May 20 by Dietmar 1
sonyu Posted May 20 Posted May 20 (edited) On 5/17/2025 at 10:25 AM, reboot12 said: First time WinXP 32-bit on UEFI 64-bit using CSMWrap 1.1.0 I follow all the improvements and tests you all do with XP these days (acpi, backported drivers, uefi boot, longhorn files...) and I don't want to go offtopic, but I need to ask something considering this topic... There are a lot of Baytrail Intel Atom tablets with a x64 cpu and 32UEFI bios which, until today, can only boot 32 bit windows. Since some years ago people managed to boot 64 Linux on them but it seems and still is impossible to install/boot Windows 64 on them. With CSMWrap or your findings, do you know if there is a change to install and boot x64 windows on these x64 atom baytrail cpus? There are tons of tablets and low powered devices with this cpu. https://superuser.com/questions/1055305/installing-windows-x64-on-32-bit-uefi-efi-ia32-via-grub Just asking because lot of people is waiting for this since a decade ago. Just search for: "UEFI32 / 64-bit OS" or https://www.google.com/search?q=Install+windows+64+bit+Intel+Baytrail+Atom+with+32+bit+UEFI Long story short about the linux: https://github.com/maharmstone/quibble/issues/2 https://github.com/Manouchehri/vi8/issues/4#issuecomment-135216613 well, just asking if this topic can help booting x64 windows on UEFI32 and x64 CPU like z3735 / z37370 Please don't consider this question full offtopic cause it's related to UEFI boot and Windows. So... maybe there is a change to boot X64 Windows in non-UEFI mode in UEFI32 baytrail? I didn't read all comments in the topic... just asking if there's a way in 2025... Thanks to all for your amazing work! Edited May 20 by sonyu
reboot12 Posted May 21 Posted May 21 (edited) 6 hours ago, sonyu said: So... maybe there is a change to boot X64 Windows in non-UEFI mode in UEFI32 baytrail? Yes of course. You need use CSMWrap ia32 32-bit version: P.S. I purposely bought such a laptop - Asus T100TAF for testing but I bricked it when I changed the hidden settings in CMOS - I need reprogramming bios - probably need desolder SPI chip: https://www.elektroda.pl/rtvforum/topic4120094.html My tests before CSMWrap was released: https://forums.mydigitallife.net/threads/winxp-32-bit-on-a-modern-pc-iso-boot-wim-install-wim.88834/#post-1873937 Many laptops with UEFI32 have an eMMC drive - I don't know if there will be a problem with that. If the laptop has a normal SATA drive it should be OK. @Dietmar Do you still have Lenovo Flex 10 with UEFI32? Edited May 21 by reboot12
Dietmar Posted May 21 Posted May 21 @reboot12 All my Lenovo Flex 10 have UEFI64. I put an UEFI32 Bios on one of them, after this it does not boot anymore Dietmar
Dietmar Posted May 21 Posted May 21 @reboot12 I think, even in the new 1.2 version of the csmwraper there is no INT13h support, https://github.com/FlyGoat/csmwrap/releases/tag/1.2.0 which means, that it cant recognice any boot devices on a compi without any CSM support Dietmar
reboot12 Posted May 22 Posted May 22 8 hours ago, Dietmar said: I think, even in the new 1.2 version of the csmwraper there is no INT13h support, No, CSMWrap support all BIOS services: Quote The truth is all BIOS interrupt service, including INT13h are always handled by SeaBIOS which is a part of CSMWrap. If there is any problem on recognising boot device, it might be caused by this issue, or ARL's PCI issue, or maybe another SeaBIOS driver issue. https://github.com/FlyGoat/csmwrap/issues/14#issuecomment-2899365096
reboot12 Posted May 22 Posted May 22 (edited) I test this build and now AHCI works on Asus H61 (Sandy Bridge) (test winload.exe because ntldr not works with iGPU) https://github.com/FlyGoat/csmwrap/actions/runs/15173994519 On Asus B85 (Haswell) other problem and don't detect any boot devices - stuck on: SeaBIOS (version efafa75-CSMWrap-34ee5ec) Version 1.2.0 not works with AHCI on Asus H61 Edited May 22 by reboot12
Dietmar Posted May 22 Posted May 22 (edited) I make a try to explain, why any UEFI-BIOS without INT13h support will fail with this csmwraper. On a legacy BIOS board, the firmware must implement INT 13h or booting raw disk sectors is impossible. A BIOS without INT 13h would be non-functional for disk boot. On a UEFI board with CSM, the firmware provides a small real-mode stub (the “thunk” you saw in CSMWRAPx64.efi in code downwards) so that INT 13h calls are trapped and redirected through UEFI Block I/O under the covers—again, preserving legacy OS compatibility. On a UEFI-only board without CSM, there is no INT 13h. And that’s the problem here if you try to boot a legacy OS that needs INT 13h Dietmar You find this in csmwraper.efi 1.2 C3 ; RET CD 02 ; INT 02h CB ; RETF CD 05 ; INT 05h CB ; RETF CD 10 ; INT 10h CB ; RETF → CD 13 ; INT 13h ← our disk service CB ; RETF CD 15 ; INT 15h CB ; RETF Edited May 22 by Dietmar
Dietmar Posted May 22 Posted May 22 (edited) Here is a try, to use direct UEFI for to integrate INT13h into the csmwraper.efi /* * CsmWrapper_Int13h_Native.c * * Integrates a native-UEFI “INT 13h” thunk into the existing CSMWrapx64.efi module. * This lets legacy OS installers (e.g. Windows XP SP3) call INT 13h and have it * translated into UEFI Block I/O, without any real-mode RETF stubs or BIOS ROM. * * Build & deploy: * 1. Disable Secure Boot (or enroll your signing key). * 2. Add this file into your PlatformPkg’s CSMWrap DXE driver (e.g. CsmWrapperDxe). * • Update the INF/DSC to compile and link it with CsmWrapperDxe. * 3. Rebuild your firmware/EDK II package. * 4. Flash or drop the new CSMWrapx64.efi into EFI\Boot\BootX64.efi (or your driver store), * ensuring it loads before any OS bootloader. * * Now, XP SP3’s INT 13h calls will be intercepted and serviced via UEFI Block I/O. */ #include <Uefi.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/BaseLib.h> #include <Library/DebugLib.h> #include <Protocol/BlockIo.h> // 1. Thunk frame matching BIOS registers: #pragma pack(1) typedef struct { UINT8 AH; // Function (0x02=read, 0x03=write) UINT8 AL; // Sector count UINT8 CH; // Cylinder UINT8 CL; // Sector (1-based) UINT8 DH; // Head UINT8 DL; // Drive (0x00=A:, 0x80=first HDD) UINT64 BufferPtr; // 64-bit pointer to data buffer UINT8 CF; // Carry Flag (output) UINT8 AH_out; // AH output (error code) } INT13_FRAME; #pragma pack() // 2. Map EFI_STATUS → BIOS AH: STATIC UINT8 MapEfiStatusToBiosError ( IN EFI_STATUS Status ) { if (Status == EFI_NOT_FOUND) return 0x01; // invalid function/device if (Status == EFI_NO_MEDIA) return 0x02; // no media if (Status == EFI_DEVICE_ERROR) return 0x20; // controller failure return 0xFF; // unknown error } // 3. Native-UEFI INT13h handler: EFI_STATUS EFIAPI Int13hNativeHandler ( IN VOID *Context ) { INT13_FRAME *F = Context; EFI_STATUS Status; EFI_BLOCK_IO_PROTOCOL *BlkIo = NULL; EFI_HANDLE *Handles = NULL; UINTN NumHandles, Index; UINT64 Lba; UINTN BufferSize; // 3.a) Enumerate all Block I/O devices Status = gBS->LocateHandleBuffer( ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &NumHandles, &Handles); if (EFI_ERROR(Status)) { F->CF = 1; F->AH_out = MapEfiStatusToBiosError(Status); return EFI_SUCCESS; } // 3.b) Pick the HDD matching DL (0x80 = first fixed disk) for (Index = 0; Index < NumHandles; ++Index) { Status = gBS->OpenProtocol( Handles[Index], &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (!EFI_ERROR(Status) && BlkIo->Media != NULL && !BlkIo->Media->Removable && F->DL == 0x80 /* + partition offset if needed */) { break; } BlkIo = NULL; } if (BlkIo == NULL) { F->CF = 1; F->AH_out = 0x01; goto Cleanup; } // 3.c) Convert CHS → LBA Lba = ((UINT64)F->CH * (BlkIo->Media->Heads + 1) + F->DH) * BlkIo->Media->Sectors + (F->CL - 1); // 3.d) Buffer size = AL * block size BufferSize = (UINTN)F->AL * BlkIo->Media->BlockSize; // 3.e) Execute read/write if (F->AH == 0x02) { Status = BlkIo->ReadBlocks( BlkIo, BlkIo->Media->MediaId, Lba, BufferSize, (VOID*)(UINTN)F->BufferPtr); } else if (F->AH == 0x03) { Status = BlkIo->WriteBlocks( BlkIo, BlkIo->Media->MediaId, Lba, BufferSize, (VOID*)(UINTN)F->BufferPtr); } else { Status = EFI_UNSUPPORTED; } // 3.f) Return CF/AH_out if (EFI_ERROR(Status)) { F->CF = 1; F->AH_out = MapEfiStatusToBiosError(Status); } else { F->CF = 0; F->AH_out = 0; } Cleanup: if (Handles) { gBS->FreePool(Handles); } return EFI_SUCCESS; } // 4. IVT patching stub (to call Int13hNativeHandler): VOID RegisterNativeInt13Thunk ( VOID ) { // // In CsmWrapperInitialize(): // 1. Use the existing real-mode 0–1MiB window (e.g. at 0x80000). // 2. Place your dispatcher stub + INT13_FRAME there. // 3. Compute PhysAddr of the stub. // 4. Patch IVT vector 0x13: // IoWrite16(0x0098, (UINT16)(PhysAddr & 0xFFFF)); // Offset // IoWrite16(0x009A, (UINT16)(PhysAddr >> 4)); // Segment // 5. Ensure your dispatcher calls Int13hNativeHandler(&MyFrame). // // (CSMWrap already sets up identity-mapped pages for 0–1MiB.) } // Hook RegisterNativeInt13Thunk() into your driver’s Init/Entry point. Edited May 22 by Dietmar
Dietmar Posted May 22 Posted May 22 1.) What This Patch Does Defines an INT13_FRAME struct mirroring BIOS registers (AH, AL, CH, CL, DH, DL) plus a 64-bit data pointer and CF/AH_out fields. Implements Int13hNativeHandler(), which: Enumerates all UEFI Block I/O devices. Selects the correct HDD by matching DL (0x80 = first fixed disk). Converts CHS to LBA (((CH*(Heads+1) + DH)*Sectors) + (CL-1)). Calls ReadBlocks() or WriteBlocks(). Maps the UEFI EFI_STATUS into BIOS-style CF/AH_out. 2.) Where to Insert Locate the CSMWrap DXE driver directory in your EDK II tree (e.g. PlatformPkg/Features/CompatSupport/CsmWrapperDxe/). Add CsmWrapper_Int13h_Native.c next to the existing source files. Update the INF file: [Sources] CsmWrapper_Int13h_Native.c Update your DSC (under DXE_DRIVER_LIST) so the new INF is built into CSMWrapx64.efi. 3.) IVT Patching (“RegisterNativeInt13Thunk”) CSMWrap already provides a real-mode window below 1 MiB. Reuse it: Place your dispatcher stub + INT13_FRAME in that region (e.g. at physical 0x80000). Patch the IVT vector 0x13 entries at addresses 0x0000:0098 (offset) and 0x0000:009A (segment) using: IoWrite16(0x0098, (UINT16)(PhysAddr & 0xFFFF)); // Offset IoWrite16(0x009A, (UINT16)(PhysAddr >> 4)); // Segment Ensure your dispatcher stub jumps to Int13hNativeHandler(&MyFrame) on INT 13h. Build & Deploy Compile with the EDK II/OVMF toolchain. Disable Secure Boot or sign the updated CSMWrapx64.efi. Place the new CSMWrapx64.efi on your ESP (EFI\Boot\BootX64.efi). Reboot. 5.) Expected Outcome The Windows XP SP3 installer issues INT 13h calls normally. Your native UEFI thunk intercepts and uses Block I/O to service them. XP “thinks” it’s talking to a real BIOS and can read/write disks successfully.
Dietmar Posted May 22 Posted May 22 1. No Real-Mode Environment BIOS world: 16-bit real mode, flat 0–1 MiB memory, its own stack, segment registers, and interrupt tables (IVT/GDT). UEFI-only world: 32/64-bit protected/long mode, full paging, no real-mode segments, no BIOS stack at 0x0000–0xFFFF. Result: The little RETF instructions in CSMWrap have nowhere valid to return into or switch from—so they never execute. 2. No Legacy BIOS ROM Code BIOS ROM: Carries the actual INT 13h disk routines below 1 MiB. That’s the code CD 13 jumps into to spin the platter and read sectors. UEFI-only firmware: Contains no legacy ROM image under 1 MiB. There is simply no INT 13h handler to call. Result: Even if you could perform CD 13, the CPU would vector to garbage and immediately triple-fault or hang. 3. No IVT Vector Patching CSM-enabled systems: Before loading CSMWrapx64.efi, the firmware patches the IVT at 0x0000:0098/009A so that INT 13h points at the tiny BIOS stub. UEFI-only systems: There is no IVT to patch, and the region at 0x0000–0x03FF isn’t even mapped for interrupts. Result: INT 13h invocation has absolutely nothing registered there—no handler, no fallback. 4. No Mode-Switch Plumbing With CSM: CSM code sets up CR0, paging, GDT entries, and stack pointers so you can do a far switch into real mode and back. Without CSM: The CPU never drops out of 64-bit mode. There’s no mechanism to clear CR0.PE or reload segment descriptors. Result: You can’t magically execute 16-bit BIOS code in a 64-bit world without this plumbing—so the entire stub logic is inert. 5. UEFI’s Native Disk Interface Differs Completely Legacy BIOS: Uses registers and INT 13h for disk I/O. UEFI: Uses EFI_BLOCK_IO_PROTOCOL functions (e.g., ReadBlocks()) in 64-bit code—no interrupts, no registers, no CHS. Result: Even if CSMWrap exists, XP SP3’s INT 13h calls won’t be rerouted to Block I/O because nothing is listening for them. Bottom Line for “Dummies” CSMWrapx64.efi alone is just a collection of 16-bit byte sequences (RETF, INT 13h, RETF). Without CSM, there is no behind-the-scenes BIOS “workshop” to host them: No real-mode memory or stack No BIOS ROM code under 1 MiB No interrupt vectors to catch INT 13h No mode-switch mechanism Therefore, XP SP3’s disk-read calls (INT 13h) simply go nowhere, and the installer cannot load any sectors—so the boot stalls and fails Dietmar 1
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now