)]}'
{
  "commit": "bc35b24e3ebd2996b2484b7f9ceb96a3cf25823a",
  "tree": "2ee74e8692e5a8bf88909e350bbdb70c056ee055",
  "parents": [
    "6ba671acd922ee046b257c5119b8a0f64d275473"
  ],
  "author": {
    "name": "Michael Brown",
    "email": "mcb30@ipxe.org",
    "time": "Wed Feb 02 03:26:20 2022 +0000"
  },
  "committer": {
    "name": "Michael Brown",
    "email": "mcb30@ipxe.org",
    "time": "Wed Feb 02 13:34:50 2022 +0000"
  },
  "message": "[prefix] Fix use of writable code segment on 486 and earlier CPUs\n\nIn real mode, code segments are always writable.  In protected mode,\ncode segments can never be writable.  The precise implementation of\nthis attribute differs between CPU generations, with subtly different\nbehaviour arising on the transitions from protected mode to real mode.\n\nAt the point of transition (when the PE bit is cleared in CR0) the\nhidden portion of the %cs descriptor will retain whatever attributes\nwere in place for the protected-mode code segment, including the fact\nthat the segment is not writable.  The immediately following code will\nperform a far control flow transfer (such as ljmp or lret) in order to\nload a real-mode value into %cs.\n\nOn the Pentium and later CPUs, the retained protected-mode attributes\nwill be ignored for any accesses via %cs while the CPU is in real\nmode.  A write via %cs will therefore be allowed even though the\nhidden portion of the %cs descriptor still describes a non-writable\nsegment.\n\nOn the 486 and earlier CPUs, the retained protected-mode attributes\nwill not be ignored for accesses via %cs.  A write via %cs will\ntherefore cause a CPU fault.  To obtain normal real-mode behaviour\n(i.e. a writable %cs descriptor), special logic is added to the ljmp\ninstruction that populates the hidden portion of the %cs descriptor\nwith real-mode attributes when a far jump is executed in real mode.\nThe result is that writes via %cs will cause a CPU fault until the\nfirst ljmp instruction is executed, after which writes via %cs will be\nallowed as expected in real mode.\n\nThe transition code in libprefix.S currently uses lret to load a\nreal-mode value into %cs after clearing the PE bit.  Experimentation\nshows that only the ljmp instruction will work to load real-mode\nattributes into the hidden portion of the %cs descriptor: other far\ncontrol flow transfers (such as lret, lcall, or int) do not do so.\n\nWhen running on a 486 or earlier CPU, this results in code within\nlibprefix.S running with a non-writable code segment after a mode\ntransition, which in turn results in a CPU fault when real-mode code\nin liba20.S attempts to write to %cs:enable_a20_method.\n\nFix by constructing and executing an ljmp instruction, to trigger the\nrelevant descriptor population logic on 486 and earlier CPUs.  This\nljmp instruction is constructed on the stack, since the .prefix\nsection may be executing directly from ROM (or from memory that the\nBIOS has write-protected in order to emulate an ISA ROM region) and so\ncannot be modified.\n\nReported-by: Nikolai Zhubr \u003cn-a-zhubr@yandex.ru\u003e\nSigned-off-by: Michael Brown \u003cmcb30@ipxe.org\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "ffb2110583508d26b9fcd4f37587278f3d69b717",
      "old_mode": 33188,
      "old_path": "src/arch/x86/prefix/libprefix.S",
      "new_id": "d7f26195719c98b5d834d9b99b561825fbb28b6c",
      "new_mode": 33188,
      "new_path": "src/arch/x86/prefix/libprefix.S"
    }
  ]
}
