Basically it appeared that without this fix, the CPU was somehow residing
in an inconsistent state, that made it crash when a full 16-bit real-mode
to 32-bit protected mode transition occurred. (Encountered when trying
to load Linux, see problem description below.)
In that situation, Bochs reports that the CPU is in "compatibility mode".
The fix is based from information from Fig.1-6 "Operating Modes of the
AMD64 Architecture" (page 12) and Chapter 14 (pages 429-446) of the
"AMD64 Architecture Programmer’s Manual Volume 2: System Programming"
https://www.amd.com/system/files/TechDocs/24593.pdf
*** THE PROBLEM ***
When booting Linux using x86 FreeLdr everything goes well.
When trying to do the same using x64 FreeLdr, the Linux code (both the
boot sector, the setup sector and the main kernel contents) is all
correctly loaded and relocated in memory as in the x86 case. We then pass
control to the decompressing code that appears to succeed. However, once
it has finished and "Parsing ELF file..." step has been run, the next
step "Booting the kernel..." crashes with a CPU Triple-Fault.
This problem **DOES NOT HAPPEN** when booting from GRUB.
Log excerpt from Bochs:
<snip>
00089459736i[BIOS ] Booting from 07c0:0000
00089782775i[SER ] com1: FIFO enabled
00095994535i[BIOS ] int13_harddisk: function 41, unmapped device for ELDL=81
00095998517i[BIOS ] int13_harddisk: function 08, unmapped device for ELDL=81
00397139785i[BIOS ] KBD: unsupported int 16h function 03
00397143625i[BIOS ] *** int 15h function AX=e980, BX=0000 not yet supported!
00523008104e[CPU0 ] interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x0
00523008104e[CPU0 ] interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x0
00523008104i[CPU0 ] CPU is in compatibility mode (active)
00523008104i[CPU0 ] CS.mode = 32 bit
00523008104i[CPU0 ] SS.mode = 32 bit
00523008104i[CPU0 ] EFER = 0x00000500
00523008104i[CPU0 ] | RAX=00000000e0000011 RBX=0000000000000000
00523008104i[CPU0 ] | RCX=0000000000000000 RDX=0000000000000000
00523008104i[CPU0 ] | RSP=00000000004f8000 RBP=000000000082e003
00523008104i[CPU0 ] | RSI=0000000000099800 RDI=00000000c0611000
00523008104i[CPU0 ] | R8=0000000000109000 R9=0000000000009020
00523008104i[CPU0 ] | R10=00000000000007e3 R11=000000000000e958
00523008104i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00523008104i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00523008104i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00523008104i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00523008104i[CPU0 ] | CS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | DS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | SS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | ES:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | FS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | GS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | MSR_FS_BASE:0000000000000000
00523008104i[CPU0 ] | MSR_GS_BASE:0000000000000000
00523008104i[CPU0 ] | RIP=0000000000409327 (0000000000409327)
00523008104i[CPU0 ] | CR0=0xe0000011 CR2=0x0000000000409327
00523008104i[CPU0 ] | CR3=0x005b5000 CR4=0x000000a0
00523008104i[CPU0 ] 0x0000000000409327: (instruction unavailable) page not present
00523008104p[CPU0 ] >>PANIC<< exception(): 3rd (13) exception with no resolution
<snip>
- Introduce "Relocator16Boot()". So far its aim is just to correctly set
the CPU state (segments, registers, flags) to what is expected by a
given boot image before running it.
This function can be seen as the embryonic state of a future boot relocator
(see e.g. GRUB or SYSLINUX) that would also relocate the boot image at
the correct places. (Such feature is needed when boot images have to
be loaded in memory areas that cover where the boot loader is in memory.)
- Implement ChainLoadBiosBootSectorCode() around it.
- Replace BootOldLinuxKernel() and BootNewLinuxKernel() by a new
BootLinuxKernel() function (in assembly) that relocates the kernel
to a given position and then boot it, using Relocator16Boot().
Ideally the relocation should be done by a future boot relocator...
Implementation notes for Relocator16Boot():
===========================================
For setting the CPU state the function is based on a similar code as the
Int386() helper, namely it takes a pointer to REGS structure and pass
this information through the 32->16 bits call before setting the CPU state
in accordance.
New stack segment/pointer and code segment/pointer are also specified.
For passing these values through the 32->16 bits call the 16-bit BSS
memory offsets "BSS_CallbackReturn" and "BSS_RealModeEntry" (respectively)
are reused.
On Windows <= 2003 (and current ReactOS), this is the "InfName" value
in the "HKEY_LOCAL_MACHINE\CurrentControlSet\Control\BiosInfo\" key.
(The default file name found there is 'biosinfo.inf'.)
On Vista+, this is the "InfName" value in the
"HKEY_LOCAL_MACHINE\CurrentControlSet\Control\Errata\" key.
(The default file name found there is 'errata.inf'.)
For 1st-stage setup, the file is specified in the "InfName" value of
the "BiosInfo" section in the TXTSETUP.SIF file.
Co-authored-by: Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Do not read the whole cluster chain for file on opening.
This removes restriction for opening files which span
within a large amount of clusters (>65k). That happened because
FrLdrTempAlloc cannot allocate more than about 256 KiB of memory.
Adjacent clusters for file are now read using one disk driver call.
According to the Advanced RISC Computing Specification v1.2, for partitions,
StartingAddress and EndingAddress are the start and end positions of the
partition in terms of byte offsets from the start of the disk.
CurrentAddress is the current offset into (i.e. relative to) the partition.
Fix also the FAT filesystem in accordance.
- FIXME fix: Retrieve the size of the disk in number of sectors in DiskOpen().
- Add extra validity checks in the DiskSeek() functions.
- Explicitly call PcDisk* functions in machpc.c and pcdisk.c, and
XboxDisk* functions in machxbox.c (the code in these files is not
called cross-platform).
CORE-16216 CORE-16248
- Modify DiskReportError() to use an internal "display counter", so that
imbricated DiskReportError(FALSE) ... DiskReportError(TRUE) can behave
as expected.
- Merge LoadAndBootDrive(), LoadAndBootPartition(),
LoadAndBootBootSector() into one LoadAndBootDevice() function + its
helpers (in progress...).
- "FrldrBootPath" -> "FrLdrBootPath";
- Get rid of GetFreeLoaderVersionString() and use FrLdrVersionString
directly instead;
- Rephrase some comments;
- Use RTL_NUMBER_OF();
- Reduce indent level in LoadOperatingSystem() and EditOperatingSystemEntry().
Bug fix:
- Fix DissectArcPath() for "ramdisk(0)" case.
- Move DiskStopFloppyMotor() calls into the implementations of
Boot(New)LinuxKernel() and Reboot() HW functions, and the explanation
comments in ChainLoadBiosBootSectorCode().
- Remove unneeded DiskStopFloppyMotor() dummies in ARM and PPC code.
- Use more adequate bitmask value to be sent to floppy's Digital Output
Register for shutting down its motor (based on OSDev & our floppy
controller driver).
- Add optional arguments BootDrive and BootPartition to
ChainLoadBiosBootSectorCode() so as not to modify explicitly the
FrldrBootDrive and FrldrBootPartition variables, that should remain
purely internal.
- Implement ChainLoadBiosBootSectorCode() for x64.
- Get rid of the machine-specific DiskGetBootPath(), and instead do its
job only once in the machine-specific InitializeBootDevices() (or in
MachInit() for PPC).
Cache the result of this operation into the globally-accessible
FrldrBootPath buffer. This avoids the unneeded calls to (Mach)DiskGetBootPath()
we used to do before.
Also remove the separate distinction between the PC and XBOX versions
of this functionality.
- Move the PC-specific DiskIsDriveRemovable() and DiskGetBootPath()
as well as the disk-IO-error functionality, back into the
corresponding PC-arch files.
- Simplify IniFileInitialize(), getting rid of IniOpenIniFile().
CORE-9023
FIXES:
======
- Fix parsing of the multiboot options string.
NOTE: They are not yet treated in a case-insensitive manner!
- Fix a bug in ArcOpen() so that it correctly skips the first path
separator (after the adapter-controller-peripheral ARC descriptors).
The path separator can be either a backslash or a slash (both are
allowed according to the specs); they were also already handled
correctly in other parts of the code.
- Fix DissectArcPath() so as to:
* **OPTIONALLY** (and not mandatorily!) return the path part that follows
the ARC adapter-controller-peripheral elements in the ARC path;
* make it correctly handle the (yes, optional!!) partition() part in the
ARC path, for the multi(x)disk(y)rdisk(z) cases.
ENHANCEMENTS:
=============
- Directly retrieve the default OS entry as we enumerate them and
build their list (i.e. merge the GetDefaultOperatingSystem() helper
within InitOperatingSystemList()).
- Directly use the opened 'FreeLoader' INI section via its ID in the
different functions that need it.
- Make the custom-boot and linux loaders honour the boot options they are
supposed to support (see FREELDR.INI documentation / template).
This includes the 'BootDrive' and 'BootPartition' (alternatively the ARC
'BootPath').
This also allows them to take into account the user-specified choices in the
FreeLdr custom-boot editors.
- Modify the FreeLdr custom-boot editors so as to correctly honour
the priorities of the boot options as specified in the FREELDR.INI
documentation / template.
- Use stack trick (union of structs) to reduce stack usage in the
FreeLdr custom-boot editors, because there are strings buffers that are
used in an alternate manner.
- Extract out from the editors the LoadOperatingSystem() calls, and
move it back into OptionMenuCustomBoot(), so that when this latter
function is called there is no risk of having a stack almost full.
- When building the ARC-compatible argument vector for the loaders, add
the mandatory "SystemPartition" path. This allows the loaders to NOT
call the machine-specific MachDiskGetBootPath() later on (this data is
indeed passed to them by the boot manager part of FreeLdr).
- Improve the FsOpenFile() helper so as to make it:
* return an adequate ARC_STATUS instead of a mere uninformative BOOLEAN;
* take open options, as well as a default path (optional) that would be
prepended to the file name in case the latter is a relative one.
- Make RamDiskLoadVirtualFile() return an actual descriptive ARC_STATUS
value, and make it take an optional default path (same usage as the one
in FsOpenFile() ).
+ Remove useless NTAPI .
- UiInitialize() and TuiTextToColor(), TuiTextToFillStyle(): load or
convert named settings into corresponding values using setting table and
a tight for-loop, instead of duplicating 10x the same parameter reading
logic.
- UiInitialize(): Open the "Display" INI section just once. Remove usage
of DisplayModeText[] buffer.
- UiShowMessageBoxesInSection() and UiShowMessageBoxesInArgv(): reduce
code indentation level.
ENHANCEMENTS for NT OS loader:
==============================
- Don't use MachDiskGetBootPath() but use instead the "SystemPartition"
value passed via the ARC argument vector by the boot manager
(+ validation checks). Use it as the "default path" when calling
FsOpenFile() or loading the ramdisk.
- Honour the FreeLdr-specific "Hal=" and "Kernel=" options by converting
them into NT standard "/HAL=" and "/KERNEL=" options in the boot
command line.
Note that if the latter ones are already present on the standard "Options="
option line, they would take precedence over those passed via the separate
"Hal=" and "Kernel=" FreeLdr-specific options.
Also add some documentation links to Geoff Chappell's website about
how the default HAL and KERNEL names are chosen depending on the
detected underlying platform on which the NT OS loader is running.
This fixes null pointer call bug, which was revealed in 85d44fc. Spotted by Mark Jansen. CORE-16216
Co-authored-by: Mark Jansen <mark.jansen@reactos.org>
- Add some forgotten, or move some misplaced ArcClose() calls so as
to avoid leakages in failure paths. (Thanks to Serge Gautherie for
having caught some of them.)
- Simplify some code; remove unneeded casts; use string-safe functions.
- Factor out disk & partition opening in LoadAndBootPartition() and
LoadAndBootDrive() into a LoadAndBootPartitionOrDrive() helper.
- Use ARC paths and ArcOpen()/ArcRead() instead of calling the
machine-specific BIOS-oriented DiskGetPartitionEntry() and
MachDiskReadLogicalSectors() functions to open the disk/partition
and read their boot sectors.
- Don't forget to close the opened boot sector file in LoadAndBootBootSector().
- Add assertions for DiskReadBufferSize in PcMemFinalizeMemoryMap()
and EnumerateHarddisks().
- x86/amd64 only:
* Add a DisableA20 helper for disabling the A20 line, before rebooting
back, or chain-load a boot sector, into 16-bit world.
Also pulse the output port of the keyboard controller to clear out
its state after having set the state of the A20 line.
* In addition to disabling the A20 line when rebooting or chain-loading
a boot sector, reset the video back to 80x25 text mode.
- Reset the cursor position back to the origin when initializing or
terminating the TUI.
- Get rid of the FsCloseFile(), FsReadFile(), FsGetFileInformation(),
FsGetFileSize() and FsSetFilePointer() wrappers and use the ARC
functions directly instead. Make FsOpenFile() return an ARC file
descriptor ID of the correct type. Get rid of unused FS_* defines.
- Use TRACEs in the ***Mount() filesystem functions for diagnostics
purposes.
- Remove a leak in FatGetFatEntry(). Assign stuff via QuadPart where
possible in FatMount(). Remove an unused member in FAT_FILE_INFO.
- Reduce code indentation in BtrFsMount() and remove a leak there.
- Disable reading the "BootPath" parameter in the linux loader since
we don't use this parameter (yet??)