Re: having System.map reflect the running kernel

Linus Torvalds (Linus.Torvalds@cs.Helsinki.FI)
Wed, 6 Sep 1995 19:25:33 +0300


"Brandon S. Allbery KF8NH": "having System.map reflect the running kernel" (Sep 6, 6:48):
> In your message of Tue, 05 Sep 1995 07:59:21 +0300, you write:
> +-----
> | > segments with 4GB limit and then go to real mode without reloading them
> | > with 64K segments. Then one can accesss all 4GB in memory (for example
> |
> | Is this guaranteed to work? I suspect it will break on many machines
> +-----
>
> Err, how could it work?
>
> (a) In real mode segment registers contain physical addresses (left-shifted,
> but still physical addresses), not segment descriptors.
>
> (b) Even if you use v86 mode instead, you can still only wedge 16 bits into
> an address field (or address offset field) of an instruction. This is a
> major part of BIOS compatibility, so even if you could trick the processor
> into taking 32-bit addresses in v86 mode you would then be BIOS-incompatible.

Actually, a x86 is a stranger beast than you probably realize.

What the original poster suggested really _might_ work, because a x86
internally doesn't really do what you think it does by just looking at
the code.

Notably, the x86 (x>3) internally never uses the segments you give it as
such: internally it uses a "segment descriptor cache", which is
essentially a more complete version of the segment descriptors. So when
you have register DS containing the value 0xf000 in real mode, the x86
doesn't actually use that value per se (except at register load time
when it uses it to fill in the cache), it uses the DS-related entry in
the segment descriptor cache instead, which might look something like

length: 65536
linear offset: 0xf0000
permissions: rwx
default address size: 16
default data size: 16

Now, what you can do is move to protected mode, and re-load the
DS-related segment cache by doing a protected-mode segment load. You
could load the DS segment with something that covers all of memory, and
if you now return to real mode with that segment, the real-mode x86
processor core will continue to use what the segment register cache says
regardless of what mode it is in.

This gets really interesting when you start re-loading such a
"impossible" segment cache while in real mode. Loading a segment in
real mode only really changes the "offset" part of the segment cache, as
all real-mode segments are supposed to always be fixed as 16-bit 64kB
segments.

With that kind of setup, it's entirely possible that a real-mode
instruction that changes a segment register only actually changes the
offset part of the cache and leaves the other entries unchanged. I
don't know if the x86 core actually works like this: I haven't tested
this part (it may be that a segment register load will also always reset
the other fields to the real-mode defaults).

And if reloading a segment doesn't change the offset and data size
defines, you can end up with a rather strange "real mode" where the
segments are > 64kB in size etc (and the size will never change by any
load/reloads you do while in real mode).

What I was arguing against was to depend on any of these features: it's
pretty much undocumented behaviour (and the x86 users manuals say that
you should reload the segments with 64kB 16-bit segments before
returning to real mode). I find it likely that this is one area where
the clones can differ from intel chips (and intel chips differ between
revisions).

But if somebody really _wants_ to be sneaky, the boot loader certaily
_could_ try to muck around with x86 segments this way..

Linus