4 ms·
In the overwhelmingly common situation where your stack started with an SP of 0, you just assign SP back to 0 before setting SS and nothing can go wrong (you ar
by caf 4y ago
In the overwhelmingly common situation where your stack started with an SP of 0, you just assign SP back to 0 before setting SS and nothing can go wrong (you are, after all, about to move off this stack and don't care about its contents).
Consider the case when the MSDOS command interpreter is handing off execution to a user program. It can't just set SP to 0 first (well, really 0xFFFF since the stack grows down), because it's somewhere several frames deep in its own execution stack, an execution stack which will hopefully resume when the user program exits.
Programs using the 'tiny' memory model, like all COM files, have SS == CS == DS so new_ss:old_sp could easily clobber the code or data from the loaded file.
- ajross 4y agoRight, so you just thunk to a different region at the bottom of your own stack in that case. I'm not saying this is easy or simple, I'm saying it's possible to do it reliably entirely in software at the OS level without the need for patching a hardware mask. Edit, just because all the folks jumping in to downvote and tell me I'm wrong are getting under my skin, this (untested, obviously) sequence should work to safely set SP to zero in an interrupt-safe way, all it requires is that you have enough space under your current stack to align SP down to a 16 bit boundary and fit 16 bytes and one interrupt frame below that. Again, you wouldn't use this in production OS code, you'd just make sure there was a frame of space at the top of your stack or be otherwise able to recover from an interrupt. But you absolutely can do this. mov %sp, %ax // Align SP down to a segment boundary and %ax, ~0xf mov %ax, %sp loop: // Iteratively: mov %ss, %ax // + decrement the segment (safe) dec %ax mov %ax, %ss mov %sp, %ax // + increment the stack pointer by the same amount (safe) add %ax, 16 mov %ax, %sp jnz loop // + Until SP is zero (and points to the same spot!)
- anyfoo 4y agoUser software is allowed to switch their stack, too, and user software must be able to be interrupted. Sure, it may be possible to work around this in software with some careful elaborate protocol that involves making sure some value of SP is usable with any value of SS, and prescribing that anything at all adhere to that (because any code at all can be interrupted by an NMI), but that not only means the use of this protocol for all stack layouts, but also implies that every single “MOV SS” or “POP SS” becomes part of some elaborate sequence of instructions (something like “push some other register on the stack, save current SP, in that register, change SP to the magic value, change SS… extra fun if you wanted POP SS, restore SP from the other register, restore the other register”). That’s a lot to put up with, and in my mind qualifies as a design bug with no palpable software workaround. Not great for wanting folks to use your brand new CPU. The protected mode transitions that you mentioned are much more palpable because they only happen in very bespoke parts of the OS kernel, usually only in bootstrap in any non-ancient OS.
- ajross 4y ago> Sure, it may be possible to work around this in software with some careful elaborate protocol Uh, yes, yes it is. That's the point. Go check the 80286 PRM for examples where the same hardware vendor inflicted far worse protocols on their users only a few years after the hack we're looking at. The subject under discussion isn't "whether or not the 8086 implemented a good stack switching interface". Clearly it did not. It's "whether the 8086 stack switching interface as designed was so irreparably broken that it required a hardware patch[1] to fix". I think the case there is pretty weak, honestly, given the state of the industry at the time. And I found it surprising that Intel would have bothered. [1] And increase interrupt latency!
- anyfoo 4y agoI’ve literally got the 80286 PRM in my room with me, the actual book, not a printout. What do you think in there is a “far worse protocol” than this abomination? And then the 286 came along at a time where the x86 architecture was already enormously successful, part of the ubiquitous IBM PC. The 8086 on the other hand was a much simpler, completely new CPU competing with many others. There aren’t many warts in the 8086 itself, whose data sheet is a few pages instead of a book (segmentation was a plus at the time because it allowed a large address space and some easy multitasking without relocation in such a simple CPU), and still it actually only won out against other CPUs for marginal reasons. If 68k had been ready for the PC, that would likely have been it. Intel had no capital at the time to inflict such an insanity to people. And why is patching the mask in a later revision of the chip such a big deal anyway?[1] Just look at the solution you proposed. Always gradually adjusting SS and SP in a loop until SP reaches 0, just because an NMI may hit. That’s untenable. [1] Interrupt latency is only slightly increased on MOV/POP SS. That shouldn’t happen so much that the much more often CLI/STI blocks with many instructions in them aren’t a bigger concern. And the 8086 wasn’t exactly low latency anyway.
- ajross 4y agoWhy is this an argument? Is it really so upsetting to you that I thought this was a weird thing to fix at the mask level? It... was. Chips in 1978 had bugs like this everywhere, and we all just dealt with it. You mentioned the 68k, for example, while forgetting the interrupt state bug that forced the introduction of the 68010! Motorola, when faced with a critical bug that would affect OS implementors in a way they could technically work around (c.f. Apollo, who used two chips) but didn't want to, didn't even bother to fix the thing and made them buy the upgraded version (obviously in some sense the '010 was the equivalent "fix it in the mask" thing). They were selling chips that couldn't restart a hardware fault well into the late 80's. > Just look at the solution you proposed. That wasn't the solution I proposed. I proposed just having the stack reserve an interrupt frame at the top and setting SP to zero before changing SS. The code I showed was just proof that even putative users[1] who couldn't change the OS would be able to work around it. [1] There were none. This was several years before MS-DOS; no one was shipping 8086 hardware in any significant quantities, certainly not to a market with binary software compatibility concerns.