GIT 1783e2f0f21444020e3dee1be46b1e34af0ea3e7 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/hpa/linux-2.6-newsetup.git commit 1783e2f0f21444020e3dee1be46b1e34af0ea3e7 Author: Venki Pallipadi Date: Wed Jun 20 14:12:39 2007 -0700 Use a new CPU feature word to cover all Intel features that are spread around in different CPUID leafs like 0x5, 0x6 and 0xA. Make this feature detection code common across i386 and x86_64. Display Intel Dynamic Acceleration feature in /proc/cpuinfo. This feature will be enabled automatically by current acpi-cpufreq driver. Refer to Intel Software Developer's Manual for more details about the feature. Thanks to hpa (H Peter Anvin) for the making the actual code detecting the scattered features data-driven. Signed-off-by: Venkatesh Pallipadi Signed-off-by: H. Peter Anvin commit cd19eb67cd6636a4e5c9df99631422c7c7286f59 Author: H. Peter Anvin Date: Wed Jun 20 14:33:17 2007 -0700 x86 setup: move __bss_start into the .bss segment Move __bss_start into the .bss segment, and create __bss_end. Signed-off-by: H. Peter Anvin commit 100327ad6b609cd28970219be57d293847d1261d Author: H. Peter Anvin Date: Wed Jun 6 22:07:01 2007 -0700 x86 setup: remove TSC as a required feature Remove TSC as a required feature, in anticipation of CONFIG_X86_TSC removal. Signed-off-by: H. Peter Anvin commit 7c91a172b8af7d4ba087f1f88ed5b155ed459ca3 Author: Antonino A. Daplas Date: Tue Jun 5 19:21:05 2007 +0800 i386: Set 6-bit DAC channel properties in vesa video setup If the video BIOS is not capable of switching or failed to switch the hardware to 8-bit DAC, the channel properties are not set. This leads to a blank (all black) display with vesafb at 8 bpp. Fix by defaulting to a 6-bit DAC. Signed-off-by: Antonino Daplas Signed-off-by: H. Peter Anvin commit 6eac2d442de8d87eac94a4ca8600bd87219fa06b Author: H. Peter Anvin Date: Tue Jun 5 16:19:36 2007 -0700 x86 setup: arch/i386/boot/cpucheck.c whitespace cleanup Remove stealth whitespace Signed-off-by: H. Peter Anvin commit f7d89f05a30433034a1b4651143afdbb2a8a9c92 Author: H. Peter Anvin Date: Thu May 24 16:56:44 2007 -0700 hd.c: remove BIOS/CMOS queries An ST-506 disk these days is pretty much someone trying to pull ancient data using an auxilliary controller. Pulling data from the BIOS or CMOS is just plain wrong, since it's likely to be the primary OS disk... and would be user-entered data anyway. Instead, require the user enters it on the command line. Signed-off-by: H. Peter Anvin commit 14c2fdb3bbfd6a9a774980e446c2443150749891 Author: H. Peter Anvin Date: Thu May 24 15:25:10 2007 -0700 x86: add back pbe bit to visible CPUID flags Add pbe back to the visible CPUID flags. We *do* correctly filter abuses of this bit for 3DNow! in all the appropriate paths. Signed-off-by: H. Peter Anvin commit e071b068a3b9f318be314f0378e655e2eb50ac89 Author: H. Peter Anvin Date: Wed May 23 14:52:34 2007 -0700 x86 setup: VIA feature mask MSR doesn't just apply to model <= 9 The VIA feature mask MSR is known to be present on model 10, and it seems likely it will continue to be supported. Since we only touch the MSR if we're about to print an error message anyway, go ahead and be aggressive. Signed-off-by: H. Peter Anvin commit abe0c5aa1827932cda9c754a3842ec22b278d704 Author: H. Peter Anvin Date: Tue May 22 17:17:41 2007 -0700 x86 setup: correct inline assembly constraints in edd.c Fix the inline assembly constraints in edd.c. In particular, "driveno" was getting clobbered on some (buggy?) BIOSes. Signed-off-by: H. Peter Anvin commit c2e5887ad275aab90673a3e33344f09946159cf7 Author: H. Peter Anvin Date: Fri May 18 10:02:55 2007 -0700 x86 setup: force the assembler to generate a 2-byte jump in header The jump instruction in the header only has two bytes available, so it *better* be a 2-byte jump! Unfortunately, the assembler will always generate a 3/5-byte jump when the target is in a different section. Deal with that by generating the jump instruction explicitly from .byte's, just like we do elsewhere when we need a specific binary representation of a certain instruction. Signed-off-by: H. Peter Anvin commit ce82e3b93eba48b6852822a03efa73c74e165d4f Author: H. Peter Anvin Date: Thu May 17 15:44:48 2007 -0700 x86 setup: move the symbol start_of_setup into the proper section. start_of_setup is the beginning of the executable code and should be located in the appropriate section. Signed-off-by: H. Peter Anvin commit e5f3a529457a5bfaf8f8783fb86013221279a81c Author: H. Peter Anvin Date: Thu May 17 15:43:19 2007 -0700 x86 setup: add an ASSERT that the header ends up in the right place Just in case we have funnies involving the linker or people putting inappropriate align statements, make the linker abort if the setup header ends up in the wrong place. Signed-off-by: H. Peter Anvin commit d9dbde725687ab99d1f529f49f14d1e280cc5cac Author: Alexander van Heukelum Date: Thu May 17 20:54:25 2007 +0200 x86 new setup: use appropriate sections for code and data An intermediate elf file is generated for the 16-bit setup code. The generated code can be viewed using objdump -m i8086 -d. As it stands, it also tries to disassemble the bugger_off_msg, which results in garbage. This introduces two new sections to separate the code and the data part of the bootsector stub. It also moves some code from the .header section (a data section) to .inittext. Signed-off-by: Alexander van Heukelum commit 0d7558a81cf61e9fd2332a54897c5fd18df0d7f2 Author: H. Peter Anvin Date: Wed May 16 22:03:16 2007 -0700 x86 setup: use -include code16gcc.h instead of explicit #include Use -include in the Makefile instead of #include to include code16gcc.h. This really is more of a compiler switch than anything else, and is a lot cleaner to do implicitly. Signed-off-by: H. Peter Anvin commit 017ce54e8a4a9628a76d6b510c7309a7e4e111a8 Author: H. Peter Anvin Date: Wed May 16 18:48:06 2007 -0700 x86 setup: enable features on Centaur (VIA) and Transmeta processors AMD are not the only ones who sometimes mask features which the kernel may very well depend on. VIA and Transmeta do, too. Add code to enable these features during checking. Signed-off-by: H. Peter Anvin commit b794f5f9c5089709f3df38c6d91869fa38a9c1a4 Author: H. Peter Anvin Date: Wed May 16 16:37:47 2007 -0700 x86 setup: in older versions of ld, ASSERT() is an expression Older versions of ld (pre-2.15 or so) need: . = ASSERT(foo, "msg"); instead of: ASSERT(foo, "msg") Signed-off-by: H. Peter Anvin commit 21c2b7c99c417d07015ee8e516a634ec3d98c4ee Author: H. Peter Anvin Date: Wed May 16 10:52:41 2007 -0700 x86 setup: print a warning message if the bootloader gave us no heap. If the bootloader is so old it doesn't set the CAN_USE_HEAP flag, a lot of functionality will by necessity be disabled, so print a warning message. This means either a 2.00 protocol bootloader or a buggy bootloader; the Qemu bootloader falls in this category. Signed-off-by: H. Peter Anvin commit 52ca0431390d389a2a2246f02fe652ea84c1ddd8 Author: H. Peter Anvin Date: Wed May 16 10:51:03 2007 -0700 x86 setup: rely on a compiled-in default for load high/load low When deciding if we should move the kernel from 0x10000 to 0x1000, as is required for a zImage kernel, rely on a compiled-in default since Qemu unconditionally zeroes the loadflags. This, of course, is a bug in Qemu, but still... Signed-off-by: H. Peter Anvin commit 4db77a97793104a32e5fb83e62b943fa144b329d Author: H. Peter Anvin Date: Wed May 16 08:45:37 2007 -0700 x86 setup: correct assembly constraints. Double use of "d" in an asm() constraints; most gcc versions correctly detect and avoid using it, but some version of gcc runs itself into a brick wall instead. Fix the one "d" which should have been "a". Signed-off-by: H. Peter Anvin commit 4fbccbc1457d6710d3a9ce55ad70ec6cb0b75fc5 Author: H. Peter Anvin Date: Tue May 15 09:16:29 2007 -0700 x86 setup: include not brings in the accessor functions, which may potentially bring in all other kinds of kernel headers which are inappropriate for the setup code. For the setup code, include instead, which only includes the numeric constants. Signed-off-by: H. Peter Anvin commit 839cafa9c0020e7506722dd2a4fd82a71c2939cc Author: H. Peter Anvin Date: Mon May 14 15:49:01 2007 -0700 x86 setup: protocol 2.0[01]: base for CL_OFFSET depends on setup_move_size Handle the use of boot protocol 2.00 and 2.01: the base segment for CL_OFFSET depends on the value of setup_move_size. Signed-off-by: H. Peter Anvin commit d60357ad68a694b03e9b952eadba5ac277c31df0 Author: H. Peter Anvin Date: Sat May 12 12:18:53 2007 -0700 x86 setup: remove unused variable Remove unused variable Signed-off-by: H. Peter Anvin commit e21a2030b01081612259847321bcce13eae1e883 Author: Sam Ravnborg Date: Sat May 12 12:17:30 2007 -0700 x86 setup: share i386 Makefile with x86_64 The boot Makefile for i386 and x86_64 are equal except for the CFLAGS setting. Teach x86_64 to use the Makefile from i386 and make CFLAGS setting arch dependent in i386 Makefile. Signed-off-by: Sam Ravnborg Signed-off-by: H. Peter Anvin commit 8618d92339d0d106045f98f34833d863c3235cdb Author: H. Peter Anvin Date: Sat May 12 00:32:12 2007 -0700 x86 setup: video-bios.c missed the pointer to the set_mode method! We need the actual pointer to the set_mode method (oops!) Signed-off-by: H. Peter Anvin commit 85dfc374ea9aad33b9e0315f07a4b2722dc11e3e Author: H. Peter Anvin Date: Sat May 12 00:14:43 2007 -0700 x86 setup: when setting unknown BIOS modes and failing, try to revert If we set an unknown BIOS mode and fail, then explicitly try to revert to the original mode. Signed-off-by: H. Peter Anvin commit f4f7949f126d2f152b09fa9367b1ec693f2ea818 Author: H. Peter Anvin Date: Fri May 11 11:20:59 2007 -0700 x86 setup: fix typo "video_bios" should be "video-bios" Signed-off-by: H. Peter Anvin commit 51ba7113ea5b07189b7f8a0534d400a072535197 Author: H. Peter Anvin Date: Fri May 11 11:09:55 2007 -0700 x86 setup: allow setting VESA modes "blind" Apparently, people really do set VESA modes "blind". As a result, make the framework for settting blind modes more general, to remove some special cases. Signed-off-by: H. Peter Anvin commit 1b8f73d9b2bf7630a2914ddab606db16fddb509e Author: H. Peter Anvin Date: Thu May 10 22:08:45 2007 -0700 x86_64: CONFIG_PHYSICAL_ALIGN should be 2 MB It's not actually used yet, but set CONFIG_PHYSICAL_ALIGN to 2 MB as it should be, to prevent conflicts with other works in progress. Signed-off-by: H. Peter Anvin commit b81f3c88923e4470cd0942d4596fafc0fb1cf4fd Author: H. Peter Anvin Date: Thu May 10 19:11:32 2007 -0700 x86 setup: remove debugging statements Remove debugging statements in video.c that were not meant for production. Signed-off-by: H. Peter Anvin commit be58b6d7e9c14e482bce495e8343955999dea77f Author: H. Peter Anvin Date: Thu May 10 18:49:40 2007 -0700 x86 setup: only restore the screen image when needed Only restore the screen image when needed. This is how the original code behaves, so it's presumably the desired behaviour. Signed-off-by: H. Peter Anvin commit 22f6bd8cc23b512af28e34ae7d40036982a0ac63 Author: H. Peter Anvin Date: Thu May 10 18:44:08 2007 -0700 x86 setup: correct the definition of the GDT limit Like all other x86 segment limits, the GDT limit points to the last byte that is *permitted* to access, so it needs to be sizeof(boot_gdt)-1. Signed-off-by: H. Peter Anvin commit 7f73f1f4aa4c97745bffe07a3ebcf226a4965b00 Author: H. Peter Anvin Date: Thu May 10 15:47:48 2007 -0700 x86 setup: Re-implement scanning for hidden video modes Re-implement scanning for hidden video modes. Every now and then, apparently, you can find them hidden like easter eggs. Signed-off-by: H. Peter Anvin commit 6770176714bc12ec92372311ac02c14f0d22776e Author: H. Peter Anvin Date: Thu May 10 15:24:27 2007 -0700 x86 setup: whitespace cleanup Clean up stealth whitespace. Signed-off-by: H. Peter Anvin commit ba0480a3537cf471b08bdb99dae6d0780cfb1972 Author: H. Peter Anvin Date: Wed May 9 16:54:42 2007 -0700 x86: sync the CPU feature string arrays With unified, synchronize the CPU feature string arrays. The whole kernel/cpu directory really needs to be unified. Signed-off-by: H. Peter Anvin commit ecb53b84efddbad3d9aa49e95598550831324348 Author: H. Peter Anvin Date: Tue May 8 22:06:04 2007 -0700 x86 setup: need to set orig_video_isVGA After detecting a VGA console, we need to set boot_params.screen_info.orig_video_isVGA. Signed-off-by: H. Peter Anvin commit dc97fc053faff17b984ec962686caea52bd27628 Author: H. Peter Anvin Date: Tue May 8 20:51:17 2007 -0700 x86 setup: boot sector should use ljmp, not jmpl We have an "jmpl" instruction in the boot sector, which was meant to be an "ljmp" instruction. It worked anyway because gas interpreted a two-argument "jmpl" as an "ljmpl" instruction, however, use plain "ljmp" (i.e. "ljmpw".) Signed-off-by: H. Peter Anvin commit 7907f05e9692557c53c9ac13647db5e5343c7c76 Author: H. Peter Anvin Date: Tue May 8 20:27:10 2007 -0700 x86 setup: only make VESA graphics modes selectable if CONFIG_FB If we select a VESA graphics mode, we better have framebuffer support or the user will have no console. Therefore, make these modes non-selectable if CONFIG_FB is not set. Signed-off-by: H. Peter Anvin commit 8e509f9ebc44f45544d231454e84f10bf78d5772 Author: H. Peter Anvin Date: Tue May 8 20:24:11 2007 -0700 x86 setup: need to probe VESA EDID block 0 only The VESA EDID BIOS call takes the EDID block number in %dx, and may corrupt it by spec. Pass it in properly. Signed-off-by: H. Peter Anvin commit 9912b9aed7943773d1fadaa2e2e52f42af395048 Author: H. Peter Anvin Date: Mon May 7 18:22:04 2007 -0700 x86 setup: add missing file "bitops.h" missing from previous checkins The file "bitops.h" was missing from previous checkins. Signed-off-by: H. Peter Anvin commit 732eb3fac2d772980e6555b8c69902c8107c72aa Author: H. Peter Anvin Date: Mon May 7 14:59:43 2007 -0700 x86 setup: add -fno-stack-protector; other Makefile fixes Add -fno-stack-protector for the gcc's that need that; Use -ffreestanding consistently; Use $(LINUXINCLUDE); Handle linker scripts consistently with other Makefiles. Signed-off-by: H. Peter Anvin commit 2d5e47f21202e156fe97aba0a88d158d5c157a33 Author: H. Peter Anvin Date: Mon May 7 14:45:25 2007 -0700 x86 setup: swap cpu.c and cpucheck.c; rename functions Make cpucheck.c the reusable component; the generically-named cpu.c gets to be the wrapper. Accordingly, rename functions to make it less confusing. Signed-off-by: H. Peter Anvin commit bf2a428a4e7c1ee3ab9acb23cfafb45e818887a1 Author: H. Peter Anvin Date: Mon May 7 14:09:38 2007 -0700 x86 setup: remove code moved from cpucheck.c -> cpu.c Move all info about requirements into cpu.c. Signed-off-by: H. Peter Anvin commit 9ea8429fabe5df6aed6393ac3a00d0b64445ba6a Author: H. Peter Anvin Date: Mon May 7 09:42:51 2007 -0700 x86 setup: remove double nesting of a20_test() a20_test() was invoked as either a20_test() or a20_wait(), where the latter was simply a loop around a loop. Make the count a parameter instead; this is clearer and saves a couple of bytes. Signed-off-by: H. Peter Anvin commit 9edc55718f57195c664ee3175514d652f651cfd2 Author: H. Peter Anvin Date: Mon May 7 09:30:41 2007 -0700 x86 setup: compile with -fomit-frame-pointer Compiling with -fomit-frame-pointer reduces the size by about 2%. Signed-off-by: H. Peter Anvin commit e1003433f2d491bf17c79437cd75268da220dab5 Author: H. Peter Anvin Date: Mon May 7 09:30:04 2007 -0700 x86 setup: be more paranoid about the stack setup in header.S In particular, deal correctly with the stack pointer being zero on entry. While we're at it, align the stack. Signed-off-by: H. Peter Anvin commit 853499c3dc3fcbeb192a613ac241d150ebc7c5a0 Author: H. Peter Anvin Date: Sun May 6 23:25:10 2007 -0700 x86 setup: Factor out the environment-independent part of the CPU check. Factor out the environment-independent part of the CPU check so it can be invoked from other parts of the kernel as well. Signed-off-by: H. Peter Anvin commit f235a61f6d6dff57883efad351d746540bcb8caf Author: H. Peter Anvin Date: Sat May 5 22:16:54 2007 -0700 x86 setup: when watching the setup size, take the stack into account When watching the setup size, we have to take the stack into account. In particular, the stack is used not only by the setup code itself, but by BIOS interrupt handlers and system calls. Reserve a minimum of 512 bytes. Signed-off-by: H. Peter Anvin commit 0d0e10091be48f7e4c8888e9d5c2836c704994f5 Author: H. Peter Anvin Date: Sat May 5 19:25:51 2007 -0700 x86 setup: actually check the end of the heap. Keep track of where the heap ends and actually watch out for it. Signed-off-by: H. Peter Anvin commit 47aab0b8f4d012fad3c42b5b0754d3cb87961b37 Author: H. Peter Anvin Date: Sat May 5 15:47:58 2007 -0700 x86 setup: coppyright rPath, Inc. This work was done on the dime of rPath, Inc.; they own the copyright. Signed-off-by: H. Peter Anvin commit d22571534d7eabf9408f29d9da423e1c6e04445f Author: H. Peter Anvin Date: Sat May 5 15:21:11 2007 -0700 x86 setup: implement screen contents save/restore The old setup code had screen contents save and restore, so implement it for the new one as well. Signed-off-by: H. Peter Anvin commit e5145601a752bd998e783d159c187d3017d45d6d Author: H. Peter Anvin Date: Sat May 5 15:20:19 2007 -0700 x86 setup: whitespace cleanup Signed-off-by: H. Peter Anvin commit 045ecb52f91a74eecad93ffc8791eefe59cf7fd1 Author: H. Peter Anvin Date: Sat May 5 14:22:39 2007 -0700 x86 setup: allow setting of VESA graphics modes; cleanups - Allow setting of VESA graphics modes (used by vesafb) - Clean up the macros related to the heap - #if 0 copy functions that aren't actually currently being used Signed-off-by: H. Peter Anvin commit 58c04ed7e2d7d5979e1917a74b49bdc0f3dde211 Author: H. Peter Anvin Date: Sat May 5 12:06:14 2007 -0700 x86 setup: move all VESA-related code into video-vesa.c; add EDID - Move all VESA-related code into video-vesa.c - Add VESA EDID query support - Remove some totally obsolete definitions from video.h Signed-off-by: H. Peter Anvin commit 07bc3931175fb98256140275c03194426d441b74 Author: H. Peter Anvin Date: Sat May 5 12:04:40 2007 -0700 x86-64: remove -traditional from AFLAGS In arch/x86_64/boot/compressed, remove -traditional from AFLAGS. Signed-off-by: H. Peter Anvin commit a830f615eeef838d461cbf7bbbee8c1c84708ec8 Author: H. Peter Anvin Date: Fri May 4 18:44:38 2007 -0700 x86 setup: share code between i386 and x86-64 Share the boot (setup) code and tools between i386 and x86-64. The compression code is now running in 64-bit mode in order to support relocation, so do *not* share that code. Signed-off-by: H. Peter Anvin commit 3e159a323bdfa5d5a7be2c1f6be089ca22d598e0 Author: H. Peter Anvin Date: Fri May 4 18:43:35 2007 -0700 x86-64: use 0x1b4 as the scratch area in boot_params, not 0x3c Use 0x1b4 as the scratch area in boot_params rather than 0x3c. Signed-off-by: H. Peter Anvin commit 4cf4424e7a0f29f251b781f9b5e3655b0645cb7f Author: H. Peter Anvin Date: Fri May 4 18:26:18 2007 -0700 Revert "x86-64: Make arch/x86-64/boot a symlink to arch/i386/boot" This reverts commit b2ad90f4969226fe8cf3edc5330711ed5fc20105. Restore arch/x86_64/boot as a separate directory hierarchy. Conflicts: commit 8ed1ae1d2f94410811b7cca4b1a426e37652457f Author: H. Peter Anvin Date: Fri May 4 17:00:33 2007 -0700 x86-64: It appears MTRR isn't a required feature after all. MTRR was documented as a required feature, but appears to boot fine without it (tested since Bochs doesn't have MTRR support.) Signed-off-by: H. Peter Anvin commit 7c616d098579fb790662cdc703f2a0f26ea1668c Author: H. Peter Anvin Date: Fri May 4 16:22:57 2007 -0700 x86 setup: use 0x1e4 as scratch, instead of 0x3c The compressed relocation needs a 4-byte scratch area to obtain its own address. 0x3c is at the end of the video area, which is quite constrained -- it only has 6 bytes left (12 if we recycle the obsolete fields which invade this space.) Define 0x1e4 as a scratch field, and use it. Signed-off-by: H. Peter Anvin commit 5bc1019227e94576e4876d05ee920f59195bce90 Author: H. Peter Anvin Date: Fri May 4 16:09:15 2007 -0700 x86 setup: boot_params.e820_map is just the map, not the count; adjust boot_params.e820_map is just a list of entries, whereas "struct e820map" contains a count as well. Thus, don't use "struct e820map" to describe struct boot_params. Signed-off-by: H. Peter Anvin commit 0f96b52497f444be2d52d1184ca90be49f713ea3 Author: H. Peter Anvin Date: Fri May 4 15:49:03 2007 -0700 x86 setup: E820MAX is a definitional constant; no need to use sizeof hacks Now when we're using the standard headers for the setup code, we can use E820MAX instead of playing sizeof games. Signed-off-by: H. Peter Anvin commit 3a23a428b20cbb31fd7ff5516a053b99afc447f7 Author: H. Peter Anvin Date: Fri May 4 12:08:46 2007 -0700 x86: move the bootparam structure definition into include/ Move the bootparam structure definition into include/, and make other things use it. Haven't cleaned up all the macros yet, though. Signed-off-by: H. Peter Anvin commit e93ec58911995971aa059990f8a91a02b05f6c8f Author: H. Peter Anvin Date: Fri May 4 12:07:50 2007 -0700 i386: change %lu to %u in arch/i386/kernel/e820.h It's an u32, print it with %u Signed-off-by: H. Peter Anvin commit 2f47f004f614e2744867c0df274c55d8af2a42d5 Author: H. Peter Anvin Date: Fri May 4 12:06:04 2007 -0700 x86: fix differences between i386 and x86-64 Fix minor differences between i386 and x86-64 Signed-off-by: H. Peter Anvin commit 56ec52f14e948f430af941052adee98019a617b7 Author: H. Peter Anvin Date: Fri May 4 11:45:17 2007 -0700 x86: fix the definition of struct screen_info Name the fields that aren't really struct screen_info, and declare the structure packed (the "capabilities" field is misaligned.) Signed-off-by: H. Peter Anvin commit 1d4429eaa564b0085d9ee3aa2de57e87a093a14e Author: H. Peter Anvin Date: Fri May 4 11:43:10 2007 -0700 x86-64: Make arch/x86-64/boot a symlink to arch/i386/boot Until such time that Kbuild allows for a cleaner solution, make arch/x86-64/boot a symlink to arch/i386/boot. Signed-off-by: H. Peter Anvin commit 6a85f1b5fd041ea99d8604782559ce0502a60cc0 Author: H. Peter Anvin Date: Fri May 4 10:42:06 2007 -0700 x86-64: rearrange includes due to unifications and inclusion from setup Unification caused a circular dependency between and ; resolve this. Add #ifndef _SETUP in so it can be included from the boot code. Signed-off-by: H. Peter Anvin commit f6bbdc254bdbd5f7cf7a40c4cd6f9844af90824a Author: H. Peter Anvin Date: Fri May 4 10:40:26 2007 -0700 x86: Complete with the union of i386 and x86-64 Add a feature to which was previously present in x86-64 but missing in i386. Signed-off-by: H. Peter Anvin commit 1a0819281060489901732914f67869e0aa8f26fd Author: H. Peter Anvin Date: Fri May 4 10:39:32 2007 -0700 x86: unify Unify between i386 and x86-64 Signed-off-by: H. Peter Anvin commit 8d9c54585f4623e0310f970fb5c6eda7ec1614df Author: H. Peter Anvin Date: Fri May 4 10:38:35 2007 -0700 x86-64: verify_cpu.S: use new masks Use the masks. Signed-off-by: H. Peter Anvin commit 6cf3308646bb7a3210f0f76bcb895b2dea76a93c Author: H. Peter Anvin Date: Fri May 4 10:37:26 2007 -0700 x86-64: fix compilation errors due to required-features.h change Fix compilation errors induced by required-features.h change. Signed-off-by: H. Peter Anvin commit 1324201a93ce380b46a3128826ecbd794e617e59 Author: H. Peter Anvin Date: Fri May 4 10:35:37 2007 -0700 x86-64: : add boot segment descriptors Add boot segment descriptors to to match i386. Signed-off-by: H. Peter Anvin commit a0b15a9e79ed0310813709cd0690d6838917fe82 Author: H. Peter Anvin Date: Fri May 4 10:34:37 2007 -0700 x86-64: add CONFIG_PHYSICAL_ALIGN to match i386 Add CONFIG_PHYSICAL_ALIGN to match i386, even though we don't use it. Signed-off-by: H. Peter Anvin commit 8f5d14d11a7318e257351ae477392c7f7e314602 Author: H. Peter Anvin Date: Fri May 4 10:33:54 2007 -0700 x86 setup: cleanups for compatibility with x86-64 These changes are necessary to compile on x86-64. Signed-off-by: H. Peter Anvin commit a32f68b6d4023c1c6b1e62e8561189516c571ab9 Author: H. Peter Anvin Date: Fri May 4 08:40:07 2007 -0700 x86 setup: add missing linker script Add linker script for the setup code, apparently missing from previous checkins. Signed-off-by: H. Peter Anvin commit 4f34ca8e926b2d0bf3a7502b99f8dfced8cdba9d Author: H. Peter Anvin Date: Thu May 3 17:42:29 2007 -0700 x86 setup: paranoia: clear the high half of %esp We're invoked in 16-bit mode from an unknown bootloader. Make sure we explicitly zero the upper half of %esp to avoid nasty surprises. Signed-off-by: H. Peter Anvin commit 19eb9b73cc1632a923003a002108b242af7a6080 Author: H. Peter Anvin Date: Thu May 3 17:35:41 2007 -0700 x86 setup: bootlin is *so* dead... Bootlin was never able to load bzImage kernels, so who cares about it. Signed-off-by: H. Peter Anvin commit 3b9fb73c65151ee043bc74c333d9e3c9b1872125 Author: H. Peter Anvin Date: Thu May 3 10:56:40 2007 -0700 x86 setup: apparently $(src) is insufficient, needs $(srctree)/$(src) For some unfanthomable reason the location of the source tree that corresponds to the current directory has to be written as $(srctree)/$(src) apparently. There might be a good reason for it, but shorthand would be appreciated, and $(src) really should be the short form. Signed-off-by: H. Peter Anvin commit a6d01d375a2269be1e3a6b31bcc4d426ad5a473d Author: H. Peter Anvin Date: Thu May 3 10:51:45 2007 -0700 x86 setup: remove reference to obsolete cpureq.c cpureq.c has been removed; remove it from the Makefile too. Signed-off-by: H. Peter Anvin commit cbe5b7585d800435080bcbf1b1fd242926982674 Author: H. Peter Anvin Date: Thu May 3 10:33:12 2007 -0700 x86 setup: use the required masks from Use the now-uniform features from . Signed-off-by: H. Peter Anvin commit 99ed30180ecc1bb4e93f6edda5f6bad1adf3e630 Author: H. Peter Anvin Date: Thu May 3 10:31:12 2007 -0700 x86: make the handling of required features consistent Make the handling of required features consistent between i386 and x86-64. Signed-off-by: H. Peter Anvin commit 1120d70a2be8f2deb6bda64047da288d8f86dad3 Author: H. Peter Anvin Date: Thu May 3 00:09:53 2007 -0700 x86: Kconfig.cpu: the minimum CPU model is always 3; WP_WORKS_OK = i486 The minimum CPU model number is always 3 (i386), and if we have WP_WORKS_OK it means we need an i486. Signed-off-by: H. Peter Anvin commit ebc308c204149b86984ae2216f5b9b2e63932028 Author: H. Peter Anvin Date: Thu May 3 00:08:48 2007 -0700 x86 setup: use CONFIG_X86_MINIMUM_CPU_MODEL Use CONFIG_X86_MINIMUM_CPU_MODEL as defined in Kconfig.cpu. Signed-off-by: H. Peter Anvin commit 8b50b640e015bf5d0f65502437da6fcab46c391b Author: H. Peter Anvin Date: Wed May 2 23:45:42 2007 -0700 x86 setup: remove bogus "static" Remove invalid "static" declarations in cpu.c Signed-off-by: H. Peter Anvin commit 35d23b60dfb110da81c24bcbfcda089cfc4fd264 Author: H. Peter Anvin Date: Wed May 2 23:37:50 2007 -0700 x86 setup: cpu detection cleanups - Use - Make sure %cr0 isn't in a dangerous configuration before probing the FPU Signed-off-by: H. Peter Anvin commit a1150a03247b355d11a4bb696b8aae1f46612992 Author: H. Peter Anvin Date: Wed May 2 23:36:55 2007 -0700 x86 setup: compile with -DSETUP Define SETUP to make it easier to share code with the rest of the kernel. Signed-off-by: H. Peter Anvin commit 7eb52e8ad1bdf01886023d1a13b3313084cd7db6 Author: H. Peter Anvin Date: Wed May 2 23:34:57 2007 -0700 x86 setup: remove unused verify_cpu.S verify_cpu.S is obsoleted by boot/cpu.c. Signed-off-by: H. Peter Anvin commit e90317a027c30176968220d18eb18bd6a9d9cc74 Author: H. Peter Anvin Date: Wed May 2 20:07:43 2007 -0700 x86 setup: files missing from previous checkin (cpu.c, cpureq.c) These files were missing from a previous checkin; CPU feature-checking code and the list of CPU features to check for. Signed-off-by: H. Peter Anvin commit 060f9b3db33c67b5344b2b4110bc823eb776e5cd Author: H. Peter Anvin Date: Wed May 2 19:51:34 2007 -0700 x86 setup: whitespace cleanup Signed-off-by: H. Peter Anvin commit 9f997a5569ec8fceaa15c2e9cf28e728e2ce118d Author: H. Peter Anvin Date: Wed May 2 19:07:14 2007 -0700 x86 setup: add CPU feature detect/abort on insufficient featurage The x86 setup is the right place to check features and abort if they are not present, since we can still get a message to the user via the firmware. Signed-off-by: H. Peter Anvin commit de4e976376fddec340651ef40b16a45f6189619d Author: H. Peter Anvin Date: Wed May 2 19:05:34 2007 -0700 x86 setup: whitespace cleanup Signed-off-by: H. Peter Anvin commit bcd2d2f8de5d4568b6628aa133fce1ac40ece526 Author: H. Peter Anvin Date: Wed May 2 16:19:59 2007 -0700 x86 setup: tag functions noreturn; error message on A20 failure Tag appropriate functions noreturn. If the A20 gate fails, output an error message and refuse to boot. Signed-off-by: H. Peter Anvin commit 752aef90cbfc888084bf11fd83f8f72b6a668fc9 Author: H. Peter Anvin Date: Wed May 2 15:45:08 2007 -0700 x86 setup: clobber registers in keyboard BIOS call Keyboard BIOS call to set repeat rate is known to clobber registers on "many" BIOSes. Signed-off-by: H. Peter Anvin commit dde94003e4759aab275732cf9f1834440cd381d0 Author: H. Peter Anvin Date: Wed May 2 15:44:21 2007 -0700 x86 setup: implement APM BIOS probe APM BIOS probe ported from assembly Signed-off-by: H. Peter Anvin commit 9403917d79e3349184318704476fa080836bd52c Author: H. Peter Anvin Date: Wed May 2 15:17:14 2007 -0700 x86 setup: remove references to obsolete probes Remove "Hello, World!" as well as references to probes which are no longer used... Signed-off-by: H. Peter Anvin commit 712f65ffbd1d4b55b4c55d68b4dcd32406c28fb8 Author: H. Peter Anvin Date: Wed May 2 12:17:15 2007 -0700 x86 setup: video.c: correct the handling of special mode numbers Special mode numbers with the high bit set need to be handled *before* masking out the high bit. Signed-off-by: H. Peter Anvin commit 9cf083204fe14cda3b09840eba8d131d2e48ccdf Author: H. Peter Anvin Date: Wed May 2 11:44:16 2007 -0700 x86 setup: Modern ATI cards pass the probe but lacks the modes. It appears modern ATI cards pass the probe for ATI-ness but lack the modes. Kill off the driver as being incorrect. Signed-off-by: H. Peter Anvin commit 890cbe950589e30af17eac9da800efc76e35e01d Author: H. Peter Anvin Date: Wed May 2 11:32:21 2007 -0700 x86 setup: a20.c: make empty_8042() return status Make functions which could reasonably return status do so. It may be relevant in the future, and it's a lot better if the programmer doesn't have to figure out where everything should hook in. Just on principle. Signed-off-by: H. Peter Anvin commit 08a44dc655e0086d23fc3c70cb93eb51eaeec259 Author: H. Peter Anvin Date: Wed May 2 11:31:03 2007 -0700 x86 setup: video.c: clean up unused stuff Clean up unused variables that we have no intent on using, as well as other cruft. Signed-off-by: H. Peter Anvin commit 57e69acff1f577de430cae1523fd49a5d113e885 Author: H. Peter Anvin Date: Wed May 2 11:18:13 2007 -0700 x86 setup: drop video mode range checking Drop video mode range checking. If someone really has, say, 12x40 mode visible through the BIOS then allow them to select it... odds are low that it will actually conflict with the very sparse allocation we have anyway. Signed-off-by: H. Peter Anvin commit c0dda0b90f92d43872d55d295630a71cd357cfa6 Author: H. Peter Anvin Date: Wed May 2 11:15:53 2007 -0700 x86 setup: if no specific video mode ID is given, generate one If we don't specify a certain video mode ID in the driver, then generate the 0xRRCC mode ID automatically. Signed-off-by: H. Peter Anvin commit 0db5086e79810e7c5d560006b1c9a7501a02d80c Author: H. Peter Anvin Date: Wed May 2 11:10:28 2007 -0700 x86 setup: Sadly, Cirrus removed extended text modes from their BIOS. In the later era of the Cirrus 54xx series, Cirrus removed extended text modes from their BIOS. Neither Qemu nor Bochs implement them in the BIOS. If we can find a direct-register-poking method of setting them that works in Bochs/Qemu it might be worthwhile to resurrect this; the probing routine *does* work. Of course, the Right Thing[TM] would be to submit such a routine to the Bochs/Qemu BIOS as a VESA text mode. Signed-off-by: H. Peter Anvin commit 41f3fddeeb764687bf3fb0cf77fd858128571d58 Author: H. Peter Anvin Date: Wed May 2 10:18:07 2007 -0700 x86 setup: remove assembly implementation of putchar and puts Already unused, remove assembly implementation of putchar and puts. Signed-off-by: H. Peter Anvin commit dfa94cd86aca2c01d2f5e14b6e7c3e8258276195 Author: H. Peter Anvin Date: Tue May 1 21:41:28 2007 -0700 x86 setup: Call INT 15h AX=E820h properly The calling convention for BIOS call 15:E820 was messed up. Signed-off-by: H. Peter Anvin commit 2487575a36435c0a983febbb4f3751331bd2df7a Author: H. Peter Anvin Date: Tue May 1 21:34:12 2007 -0700 x86 setup: advance one e820 descriptor at a time... Adding sizeof(foo) to a foo * is not just useless, it's pretty damaging... Signed-off-by: H. Peter Anvin commit 530d4f4f1732335ae8725c0b8c332a618e63ea1d Author: H. Peter Anvin Date: Tue May 1 21:33:28 2007 -0700 x86 setup: fix memcmp_[fg]s() Actually return a value from memcmp_[fg]s()... Signed-off-by: H. Peter Anvin commit 8617cd56ff2e43303147da012b26c9dd46af726e Author: H. Peter Anvin Date: Tue May 1 21:32:47 2007 -0700 x86 setup: fix missing semicolon in video-ati.c Signed-off-by: H. Peter Anvin commit 7bbf7fa3e199b9cef4877c5a56128faff8636cc9 Author: H. Peter Anvin Date: Tue May 1 21:26:48 2007 -0700 x86 setup: make the video setup code actually do something... Basic video setup now works (there is still work to be done, however.) Signed-off-by: H. Peter Anvin commit 45bcd4406e4b812b32d317d9b3b8db2e5f135a3c Author: H. Peter Anvin Date: Tue May 1 21:25:20 2007 -0700 x86 setup: segment descriptors need to be Present The segment descriptors were missing the Present bit. Signed-off-by: H. Peter Anvin commit a39479d4ccf4dceffb623ad2ec7e2d708c38c637 Author: H. Peter Anvin Date: Tue May 1 21:24:32 2007 -0700 build: setup sectors doesn't include the boot sector The "setup sectors" field doesn't include the old boot sector, even though the two are now one module. Signed-off-by: H. Peter Anvin commit d8f3d4928ead72e8febe2fcd740d0fee71a61f42 Author: H. Peter Anvin Date: Tue May 1 21:23:44 2007 -0700 x86 setup: in tty.c, actually tell it what character to print putchar() was missing the actual passing of the character code to the BIOS call, with very silly-looking results. Signed-off-by: H. Peter Anvin commit 4f1462ed0377e180484a223e622d62432baa64b7 Author: H. Peter Anvin Date: Tue May 1 21:22:46 2007 -0700 x86 setup: printf.c needs code16gcc.h printf.c was missing code16gcc.h, with predictable consequences. Signed-off-by: H. Peter Anvin commit a5ba7e6df198bd204b0f87fc6e3f68388b9d14c1 Author: H. Peter Anvin Date: Mon Apr 30 20:56:42 2007 -0700 MAINTAINERS: formally take responsibility for the i386 boot code Change MAINTAINERS to formally take responsibility for the i386 boot code. Signed-off-by: H. Peter Anvin commit 6c821fc005655a99eff6e86c2e4b13654de94dea Author: H. Peter Anvin Date: Mon Apr 30 20:54:07 2007 -0700 x86 setup code rewrite: initial development snapshot Clean up the setup code and rewrite it in C. This is an initial development snapshot, not a working tree. Signed-off-by: H. Peter Anvin Signed-off-by: Andrew Morton --- MAINTAINERS | 4 arch/i386/Kconfig.cpu | 4 arch/i386/boot/Makefile | 45 arch/i386/boot/a20.c | 161 + arch/i386/boot/apm.c | 97 arch/i386/boot/bitops.h | 45 arch/i386/boot/boot.h | 290 ++ arch/i386/boot/bootsect.S | 98 arch/i386/boot/cmdline.c | 97 arch/i386/boot/code16gcc.h | 9 arch/i386/boot/compressed/Makefile | 7 arch/i386/boot/compressed/head.S | 6 arch/i386/boot/compressed/misc.c | 3 arch/i386/boot/copy.S | 101 arch/i386/boot/cpu.c | 69 arch/i386/boot/cpucheck.c | 266 ++ arch/i386/boot/edd.S | 231 -- arch/i386/boot/edd.c | 196 + arch/i386/boot/header.S | 283 ++ arch/i386/boot/main.c | 161 + arch/i386/boot/mca.c | 43 arch/i386/boot/memory.c | 99 arch/i386/boot/pm.c | 170 + arch/i386/boot/pmjump.S | 54 arch/i386/boot/printf.c | 331 ++ arch/i386/boot/setup.S | 1075 --------- arch/i386/boot/setup.ld | 54 arch/i386/boot/string.c | 34 arch/i386/boot/tools/build.c | 156 - arch/i386/boot/tty.c | 112 arch/i386/boot/version.c | 23 arch/i386/boot/vesa.h | 79 arch/i386/boot/video-bios.c | 125 + arch/i386/boot/video-vesa.c | 283 ++ arch/i386/boot/video-vga.c | 260 ++ arch/i386/boot/video.S | 2043 ------------------ arch/i386/boot/video.c | 456 ++++ arch/i386/boot/video.h | 145 + arch/i386/boot/voyager.c | 46 arch/i386/kernel/cpu/addon_cpuid_features.c | 50 arch/i386/kernel/cpu/common.c | 2 arch/i386/kernel/cpu/proc.c | 21 arch/i386/kernel/e820.c | 2 arch/i386/kernel/setup.c | 12 arch/i386/kernel/verify_cpu.S | 94 arch/x86_64/Kconfig | 4 arch/x86_64/boot/Makefile | 136 - arch/x86_64/boot/bootsect.S | 98 arch/x86_64/boot/compressed/Makefile | 9 arch/x86_64/boot/compressed/head.S | 6 arch/x86_64/boot/install.sh | 2 arch/x86_64/boot/mtools.conf.in | 17 arch/x86_64/boot/setup.S | 826 ------- arch/x86_64/boot/tools/build.c | 185 - arch/x86_64/kernel/Makefile | 2 arch/x86_64/kernel/setup.c | 21 arch/x86_64/kernel/verify_cpu.S | 22 drivers/ide/legacy/hd.c | 73 include/asm-i386/boot.h | 6 include/asm-i386/bootparam.h | 85 include/asm-i386/cpufeature.h | 26 include/asm-i386/e820.h | 14 include/asm-i386/processor.h | 1 include/asm-i386/required-features.h | 37 include/asm-i386/setup.h | 10 include/asm-x86_64/alternative.h | 68 include/asm-x86_64/boot.h | 16 include/asm-x86_64/bootparam.h | 1 include/asm-x86_64/cpufeature.h | 115 - include/asm-x86_64/e820.h | 6 include/asm-x86_64/processor.h | 3 include/asm-x86_64/required-features.h | 46 include/asm-x86_64/segment.h | 8 include/linux/edd.h | 4 include/linux/screen_info.h | 9 75 files changed, 4594 insertions(+), 5204 deletions(-) --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1750,8 +1750,8 @@ S: Maintained i386 BOOT CODE -P: Riley H. Williams -M: Riley@Williams.Name +P: H. Peter Anvin +M: hpa@zytor.com L: Linux-Kernel@vger.kernel.org S: Maintained --- a/arch/i386/Kconfig.cpu +++ b/arch/i386/Kconfig.cpu @@ -346,6 +346,6 @@ config X86_MINIMUM_CPU_MODEL int - default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP - default "0" + default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK + default "3" --- a/arch/i386/boot/Makefile +++ b/arch/i386/boot/Makefile @@ -25,27 +25,53 @@ #RAMDISK := -DRAMDISK=512 -targets := vmlinux.bin bootsect bootsect.o \ - setup setup.o zImage bzImage +targets := vmlinux.bin setup.bin setup.elf zImage bzImage subdir- := compressed +setup-y += a20.o apm.o cmdline.o copy.o cpu.o cpucheck.o edd.o +setup-y += header.o main.o mca.o memory.o pm.o pmjump.o +setup-y += printf.o string.o tty.o video.o version.o voyager.o + +# The link order of the video-*.o modules can matter. In particular, +# video-vga.o *must* be listed first, followed by video-vesa.o. +# Hardware-specific drivers should follow in the order they should be +# probed, and video-bios.o should typically be last. +setup-y += video-vga.o +setup-y += video-vesa.o +setup-y += video-bios.o + hostprogs-y := tools/build HOSTCFLAGS_build.o := $(LINUXINCLUDE) # --------------------------------------------------------------------------- +# How to compile the 16-bit code. Note we always compile for -march=i386, +# that way we can complain to the user if the CPU is insufficient. +cflags-i386 := +cflags-x86_64 := -m32 +CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \ + $(cflags-$(ARCH)) \ + -Wall -Wstrict-prototypes \ + -march=i386 -mregparm=3 \ + -include $(srctree)/$(src)/code16gcc.h \ + -fno-strict-aliasing -fomit-frame-pointer \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-stack-protector) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + $(obj)/zImage: IMAGE_OFFSET := 0x1000 $(obj)/zImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) $(obj)/bzImage: IMAGE_OFFSET := 0x100000 +$(obj)/bzImage: EXTRA_CFLAGS := -D__BIG_KERNEL__ $(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ $(obj)/bzImage: BUILDFLAGS := -b quiet_cmd_image = BUILD $@ -cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ +cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/setup.bin \ $(obj)/vmlinux.bin $(ROOT_DEV) > $@ -$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ +$(obj)/zImage $(obj)/bzImage: $(obj)/setup.bin \ $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' @@ -53,12 +79,17 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) -LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary -LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext +SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) -$(obj)/setup $(obj)/bootsect: %: %.o FORCE +LDFLAGS_setup.elf := -T +$(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE $(call if_changed,ld) +OBJCOPYFLAGS_setup.bin := -O binary + +$(obj)/setup.bin: $(obj)/setup.elf FORCE + $(call if_changed,objcopy) + $(obj)/compressed/vmlinux: FORCE $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@ --- /dev/null +++ b/arch/i386/boot/a20.c @@ -0,0 +1,161 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/a20.c + * + * Enable A20 gate (return -1 on failure) + */ + +#include "boot.h" + +#define MAX_8042_LOOPS 100000 + +static int empty_8042(void) +{ + u8 status; + int loops = MAX_8042_LOOPS; + + while (loops--) { + io_delay(); + + status = inb(0x64); + if (status & 1) { + /* Read and discard input data */ + io_delay(); + (void)inb(0x60); + } else if (!(status & 2)) { + /* Buffers empty, finished! */ + return 0; + } + } + + return -1; +} + +/* Returns nonzero if the A20 line is enabled. The memory address + used as a test is the int $0x80 vector, which should be safe. */ + +#define A20_TEST_ADDR (4*0x80) +#define A20_TEST_SHORT 32 +#define A20_TEST_LONG 2097152 /* 2^21 */ + +static int a20_test(int loops) +{ + int ok = 0; + int saved, ctr; + + set_fs(0x0000); + set_gs(0xffff); + + saved = ctr = rdfs32(A20_TEST_ADDR); + + while (loops--) { + wrfs32(++ctr, A20_TEST_ADDR); + io_delay(); /* Serialize and make delay constant */ + ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr; + if (ok) + break; + } + + wrfs32(saved, A20_TEST_ADDR); + return ok; +} + +/* Quick test to see if A20 is already enabled */ +static int a20_test_short(void) +{ + return a20_test(A20_TEST_SHORT); +} + +/* Longer test that actually waits for A20 to come on line; this + is useful when dealing with the KBC or other slow external circuitry. */ +static int a20_test_long(void) +{ + return a20_test(A20_TEST_LONG); +} + +static void enable_a20_bios(void) +{ + asm volatile("pushfl; int $0x15; popfl" + : : "a" ((u16)0x2401)); +} + +static void enable_a20_kbc(void) +{ + empty_8042(); + + outb(0xd1, 0x64); /* Command write */ + empty_8042(); + + outb(0xdf, 0x60); /* A20 on */ + empty_8042(); +} + +static void enable_a20_fast(void) +{ + u8 port_a; + + port_a = inb(0x92); /* Configuration port A */ + port_a |= 0x02; /* Enable A20 */ + port_a &= ~0x01; /* Do not reset machine */ + outb(port_a, 0x92); +} + +/* + * Actual routine to enable A20; return 0 on ok, -1 on failure + */ + +#define A20_ENABLE_LOOPS 255 /* Number of times to try */ + +int enable_a20(void) +{ + int loops = A20_ENABLE_LOOPS; + +#if defined(CONFIG_X86_ELAN) + /* Elan croaks if we try to touch the KBC */ + enable_a20_fast(); + while (!a20_test_long()) + ; + return 0; +#elif defined(CONFIG_X86_VOYAGER) + /* On Voyager, a20_test() is unsafe? */ + enable_a20_kbc(); + return 0; +#else + while (loops--) { + /* First, check to see if A20 is already enabled + (legacy free, etc.) */ + if (a20_test_short()) + return 0; + + /* Next, try the BIOS (INT 0x15, AX=0x2401) */ + enable_a20_bios(); + if (a20_test_short()) + return 0; + + /* Try enabling A20 through the keyboard controller */ + empty_8042(); + if (a20_test_short()) + return 0; /* BIOS worked, but with delayed reaction */ + + enable_a20_kbc(); + if (a20_test_long()) + return 0; + + /* Finally, try enabling the "fast A20 gate" */ + enable_a20_fast(); + if (a20_test_long()) + return 0; + } + + return -1; +#endif +} --- /dev/null +++ b/arch/i386/boot/apm.c @@ -0,0 +1,97 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * Original APM BIOS checking by Stephen Rothwell, May 1994 + * (sfr@canb.auug.org.au) + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/apm.c + * + * Get APM BIOS information + */ + +#include "boot.h" + +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) + +int query_apm_bios(void) +{ + u16 ax, bx, cx, dx, di; + u32 ebx, esi; + u8 err; + + /* APM BIOS installation check */ + ax = 0x5300; + bx = cx = 0; + asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" + : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) + : : "esi", "edi"); + + if (err) + return -1; /* No APM BIOS */ + + if (bx != 0x504d) /* "PM" signature */ + return -1; + + if (cx & 0x02) /* 32 bits supported? */ + return -1; + + /* Disconnect first, just in case */ + ax = 0x5304; + asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" + : "+a" (ax) + : : "ebx", "ecx", "edx", "esi", "edi"); + + /* Paranoia */ + ebx = esi = 0; + cx = dx = di = 0; + + /* 32-bit connect */ + asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6" + : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx), + "+S" (esi), "+D" (di), "=m" (err) + : "a" (0x5303)); + + boot_params.apm_bios_info.cseg = ax; + boot_params.apm_bios_info.offset = ebx; + boot_params.apm_bios_info.cseg_16 = cx; + boot_params.apm_bios_info.dseg = dx; + boot_params.apm_bios_info.cseg_len = (u16)esi; + boot_params.apm_bios_info.cseg_16_len = esi >> 16; + boot_params.apm_bios_info.dseg_len = di; + + if (err) + return -1; + + /* Redo the installation check as the 32-bit connect; + some BIOSes return different flags this way... */ + + ax = 0x5300; + bx = cx = 0; + asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" + : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) + : : "esi", "edi"); + + if (err || bx != 0x504d) { + /* Failure with 32-bit connect, try to disconect and ignore */ + ax = 0x5304; + bx = 0; + asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" + : "+a" (ax), "+b" (bx) + : : "ecx", "edx", "esi", "edi"); + return -1; + } + + boot_params.apm_bios_info.version = ax; + boot_params.apm_bios_info.flags = cx; + return 0; +} + +#endif --- /dev/null +++ b/arch/i386/boot/bitops.h @@ -0,0 +1,45 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/bitops.h + * + * Very simple bitops for the boot code. + */ + +#ifndef BOOT_BITOPS_H +#define BOOT_BITOPS_H +#define _LINUX_BITOPS_H /* Inhibit inclusion of */ + +static inline int constant_test_bit(int nr, const void *addr) +{ + const u32 *p = (const u32 *)addr; + return ((1UL << (nr & 31)) & (p[nr >> 5])) != 0; +} +static inline int variable_test_bit(int nr, const void *addr) +{ + u8 v; + const u32 *p = (const u32 *)addr; + + asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); + return v; +} + +#define test_bit(nr,addr) \ +(__builtin_constant_p(nr) ? \ + constant_test_bit((nr),(addr)) : \ + variable_test_bit((nr),(addr))) + +static inline void set_bit(int nr, void *addr) +{ + asm("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr)); +} + +#endif /* BOOT_BITOPS_H */ --- /dev/null +++ b/arch/i386/boot/boot.h @@ -0,0 +1,290 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/boot.h + * + * Header file for the real-mode kernel code + */ + +#ifndef BOOT_BOOT_H +#define BOOT_BOOT_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include +#include + +/* Useful macros */ +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) + +extern struct setup_header hdr; +extern struct boot_params boot_params; + +/* Basic port I/O */ +static inline void outb(u8 v, u16 port) +{ + asm volatile("outb %0,%1" : : "a" (v), "dN" (port)); +} +static inline u8 inb(u16 port) +{ + u8 v; + asm volatile("inb %1,%0" : "=a" (v) : "dN" (port)); + return v; +} + +static inline void outw(u16 v, u16 port) +{ + asm volatile("outw %0,%1" : : "a" (v), "dN" (port)); +} +static inline u16 inw(u16 port) +{ + u16 v; + asm volatile("inw %1,%0" : "=a" (v) : "dN" (port)); + return v; +} + +static inline void outl(u32 v, u16 port) +{ + asm volatile("outl %0,%1" : : "a" (v), "dn" (port)); +} +static inline u32 inl(u32 port) +{ + u32 v; + asm volatile("inl %1,%0" : "=a" (v) : "dN" (port)); + return v; +} + +static inline void io_delay(void) +{ + const u16 DELAY_PORT = 0x80; + asm volatile("outb %%al,%0" : : "dN" (DELAY_PORT)); +} + +/* These functions are used to reference data in other segments. */ + +static inline u16 ds(void) +{ + u16 seg; + asm("movw %%ds,%0" : "=rm" (seg)); + return seg; +} + +static inline void set_fs(u16 seg) +{ + asm volatile("movw %0,%%fs" : : "rm" (seg)); +} +static inline u16 fs(void) +{ + u16 seg; + asm("movw %%fs,%0" : "=rm" (seg)); + return seg; +} + +static inline void set_gs(u16 seg) +{ + asm volatile("movw %0,%%gs" : : "rm" (seg)); +} +static inline u16 gs(void) +{ + u16 seg; + asm("movw %%gs,%0" : "=rm" (seg)); + return seg; +} + +typedef unsigned int addr_t; + +static inline u8 rdfs8(addr_t addr) +{ + u8 v; + asm("movb %%fs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr)); + return v; +} +static inline u16 rdfs16(addr_t addr) +{ + u16 v; + asm("movw %%fs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr)); + return v; +} +static inline u32 rdfs32(addr_t addr) +{ + u32 v; + asm("movl %%fs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr)); + return v; +} + +static inline void wrfs8(u8 v, addr_t addr) +{ + asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "r" (v)); +} +static inline void wrfs16(u16 v, addr_t addr) +{ + asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "r" (v)); +} +static inline void wrfs32(u32 v, addr_t addr) +{ + asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "r" (v)); +} + +static inline u8 rdgs8(addr_t addr) +{ + u8 v; + asm("movb %%gs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr)); + return v; +} +static inline u16 rdgs16(addr_t addr) +{ + u16 v; + asm("movw %%gs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr)); + return v; +} +static inline u32 rdgs32(addr_t addr) +{ + u32 v; + asm("movl %%gs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr)); + return v; +} + +static inline void wrgs8(u8 v, addr_t addr) +{ + asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "r" (v)); +} +static inline void wrgs16(u16 v, addr_t addr) +{ + asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "r" (v)); +} +static inline void wrgs32(u32 v, addr_t addr) +{ + asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "r" (v)); +} + +/* Note: these only return true/false, not a signed return value! */ +static inline int memcmp(const void *s1, const void *s2, size_t len) +{ + u8 diff; + asm("repe; cmpsb; setnz %0" + : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); + return diff; +} + +static inline int memcmp_fs(const void *s1, addr_t s2, size_t len) +{ + u8 diff; + asm("fs; repe; cmpsb; setnz %0" + : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); + return diff; +} +static inline int memcmp_gs(const void *s1, addr_t s2, size_t len) +{ + u8 diff; + asm("gs; repe; cmpsb; setnz %0" + : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); + return diff; +} + +/* Heap -- available for dynamic lists. */ +#define STACK_SIZE 512 /* Minimum number of bytes for stack */ + +extern char _end[]; +extern char *HEAP; +extern char *heap_end; +#define RESET_HEAP() ((void *)( HEAP = _end )) +static inline char *__get_heap(size_t s, size_t a, size_t n) +{ + char *tmp; + + HEAP = (char *)(((size_t)HEAP+(a-1)) & ~(a-1)); + tmp = HEAP; + HEAP += s*n; + return tmp; +} +#define GET_HEAP(type, n) \ + ((type *)__get_heap(sizeof(type),__alignof__(type),(n))) + +static inline int heap_free(void) +{ + return heap_end-HEAP; +} + +/* copy.S */ + +void copy_to_fs(addr_t dst, void *src, size_t len); +void *copy_from_fs(void *dst, addr_t src, size_t len); +void copy_to_gs(addr_t dst, void *src, size_t len); +void *copy_from_gs(void *dst, addr_t src, size_t len); +void *memcpy(void *dst, void *src, size_t len); +void *memset(void *dst, int c, size_t len); + +#define memcpy(d,s,l) __builtin_memcpy(d,s,l) +#define memset(d,c,l) __builtin_memset(d,c,l) + +/* a20.c */ +int enable_a20(void); + +/* apm.c */ +int query_apm_bios(void); + +/* cmdline.c */ +int cmdline_find_option(const char *option, char *buffer, int bufsize); + +/* cpu.c, cpucheck.c */ +int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr); +int validate_cpu(void); + +/* edd.c */ +void query_edd(void); + +/* header.S */ +void __attribute__((noreturn)) die(void); + +/* mca.c */ +int query_mca(void); + +/* memory.c */ +int detect_memory(void); + +/* pm.c */ +void __attribute__((noreturn)) go_to_protected_mode(void); + +/* pmjump.S */ +void __attribute__((noreturn)) + protected_mode_jump(u32 entrypoint, u32 bootparams); + +/* printf.c */ +unsigned int atou(const char *s); +int sprintf(char *buf, const char *fmt, ...); +int vsprintf(char *buf, const char *fmt, va_list args); +int printf(const char *fmt, ...); + +/* string.c */ +int strcmp(const char *str1, const char *str2); + +/* tty.c */ +void puts(const char *); +void putchar(int); +int getchar(void); +void kbd_flush(void); +int getchar_timeout(void); + +/* video.c */ +void set_video(void); + +/* video-vesa.c */ +void vesa_store_edid(void); + +/* voyager.c */ +int query_voyager(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* BOOT_BOOT_H */ --- a/arch/i386/boot/bootsect.S +++ /dev/null @@ -1,98 +0,0 @@ -/* - * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds - * - * modified by Drew Eckhardt - * modified by Bruce Evans (bde) - * modified by Chris Noe (May 1999) (as86 -> gas) - * gutted by H. Peter Anvin (Jan 2003) - * - * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment - * addresses must be multiplied by 16 to obtain their respective linear - * addresses. To avoid confusion, linear addresses are written using leading - * hex while segment addresses are written as segment:offset. - * - */ - -#include - -SETUPSECTS = 4 /* default nr of setup-sectors */ -BOOTSEG = 0x07C0 /* original address of boot-sector */ -INITSEG = DEF_INITSEG /* we move boot here - out of the way */ -SETUPSEG = DEF_SETUPSEG /* setup starts here */ -SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */ -SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */ - /* to be loaded */ -ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */ -SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */ - -#ifndef SVGA_MODE -#define SVGA_MODE ASK_VGA -#endif - -#ifndef RAMDISK -#define RAMDISK 0 -#endif - -#ifndef ROOT_RDONLY -#define ROOT_RDONLY 1 -#endif - -.code16 -.text - -.global _start -_start: - - # Normalize the start address - jmpl $BOOTSEG, $start2 - -start2: - movw %cs, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw $0x7c00, %sp - sti - cld - - movw $bugger_off_msg, %si - -msg_loop: - lodsb - andb %al, %al - jz die - movb $0xe, %ah - movw $7, %bx - int $0x10 - jmp msg_loop - -die: - # Allow the user to press a key, then reboot - xorw %ax, %ax - int $0x16 - int $0x19 - - # int 0x19 should never return. In case it does anyway, - # invoke the BIOS reset code... - ljmp $0xf000,$0xfff0 - - -bugger_off_msg: - .ascii "Direct booting from floppy is no longer supported.\r\n" - .ascii "Please use a boot loader program instead.\r\n" - .ascii "\n" - .ascii "Remove disk and press any key to reboot . . .\r\n" - .byte 0 - - - # Kernel attributes; used by setup - - .org 497 -setup_sects: .byte SETUPSECTS -root_flags: .word ROOT_RDONLY -syssize: .word SYSSIZE -swap_dev: .word SWAP_DEV -ram_size: .word RAMDISK -vid_mode: .word SVGA_MODE -root_dev: .word ROOT_DEV -boot_flag: .word 0xAA55 --- /dev/null +++ b/arch/i386/boot/cmdline.c @@ -0,0 +1,97 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/cmdline.c + * + * Simple command-line parser for early boot. + */ + +#include "boot.h" + +static inline int myisspace(u8 c) +{ + return c <= ' '; /* Close enough approximation */ +} + +/* + * Find a non-boolean option, that is, "option=argument". In accordance + * with standard Linux practice, if this option is repeated, this returns + * the last instance on the command line. + * + * Returns the length of the argument (regardless of if it was + * truncated to fit in the buffer), or -1 on not found. + */ +int cmdline_find_option(const char *option, char *buffer, int bufsize) +{ + u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr; + addr_t cptr; + char c; + int len = -1; + const char *opptr = NULL; + char *bufptr = buffer; + enum { + st_wordstart, /* Start of word/after whitespace */ + st_wordcmp, /* Comparing this word */ + st_wordskip, /* Miscompare, skip */ + st_bufcpy /* Copying this to buffer */ + } state = st_wordstart; + + if (!cmdline_ptr || cmdline_ptr >= 0x100000) + return -1; /* No command line, or inaccessible */ + + cptr = cmdline_ptr & 0xf; + set_fs(cmdline_ptr >> 4); + + while (cptr < 0x10000 && (c = rdfs8(cptr++))) { + switch (state) { + case st_wordstart: + if (myisspace(c)) + break; + + /* else */ + state = st_wordcmp; + opptr = option; + /* fall through */ + + case st_wordcmp: + if (c == '=' && !*opptr) { + len = 0; + bufptr = buffer; + state = st_bufcpy; + } else if (myisspace(c)) { + state = st_wordstart; + } else if (c != *opptr++) { + state = st_wordskip; + } + break; + + case st_wordskip: + if (myisspace(c)) + state = st_wordstart; + break; + + case st_bufcpy: + if (myisspace(c)) { + state = st_wordstart; + } else { + if (len < bufsize-1) + *bufptr++ = c; + len++; + } + break; + } + } + + if (bufsize) + *bufptr = '\0'; + + return len; +} --- /dev/null +++ b/arch/i386/boot/code16gcc.h @@ -0,0 +1,9 @@ +/* + * code16gcc.h + * + * This file is -include'd when compiling 16-bit C code. + */ + +#ifndef __ASSEMBLY__ +asm(".code16gcc"); +#endif --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -9,9 +9,14 @@ EXTRA_AFLAGS := -traditional LDFLAGS_vmlinux := -T -CFLAGS_misc.o += -fPIC hostprogs-y := relocs +CFLAGS := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ + -fno-strict-aliasing -fPIC \ + $(call cc-option,-ffreestanding) \ + $(call cc-option,-fno-stack-protector) +LDFLAGS := -m elf_i386 + $(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: --- a/arch/i386/boot/compressed/head.S +++ b/arch/i386/boot/compressed/head.S @@ -45,10 +45,10 @@ * at and where we were actually loaded at. This can only be done * with a short local call on x86. Nothing else will tell us what * address we are running at. The reserved chunk of the real-mode - * data at 0x34-0x3f are used as the stack for this calculation. - * Only 4 bytes are needed. + * data at 0x1e4 (defined as a scratch field) are used as the stack + * for this calculation. Only 4 bytes are needed. */ - leal 0x40(%esi), %esp + leal (0x1e4+4)(%esi), %esp call 1f 1: popl %ebp subl $1b, %ebp --- a/arch/i386/boot/compressed/misc.c +++ b/arch/i386/boot/compressed/misc.c @@ -11,7 +11,6 @@ #undef CONFIG_PARAVIRT #include -#include #include #include #include @@ -364,8 +363,10 @@ if ((u32)output & (CONFIG_PHYSICAL_ALIGN -1)) error("Destination address not CONFIG_PHYSICAL_ALIGN aligned"); +#ifndef CONFIG_X86_64 if (end > ((-__PAGE_OFFSET-(512 <<20)-1) & 0x7fffffff)) error("Destination address too large"); +#endif #ifndef CONFIG_RELOCATABLE if ((u32)output != LOAD_PHYSICAL_ADDR) error("Wrong destination address"); --- /dev/null +++ b/arch/i386/boot/copy.S @@ -0,0 +1,101 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/copy.S + * + * Memory copy routines + */ + + .code16gcc + .text + + .globl memcpy + .type memcpy, @function +memcpy: + pushw %si + pushw %di + movw %ax, %di + movw %dx, %si + pushw %cx + shrw $2, %cx + rep; movsl + popw %cx + andw $3, %cx + rep; movsb + popw %di + popw %si + ret + .size memcpy, .-memcpy + + .globl memset + .type memset, @function +memset: + pushw %di + movw %ax, %di + movzbl %dl, %eax + imull $0x01010101,%eax + pushw %cx + shrw $2, %cx + rep; stosl + popw %cx + andw $3, %cx + rep; stosb + popw %di + ret + .size memset, .-memset + + .globl copy_from_fs + .type copy_from_fs, @function +copy_from_fs: + pushw %ds + pushw %fs + popw %ds + call memcpy + popw %ds + ret + .size copy_from_fs, .-copy_from_fs + + .globl copy_to_fs + .type copy_to_fs, @function +copy_to_fs: + pushw %es + pushw %fs + popw %es + call memcpy + popw %es + ret + .size copy_to_fs, .-copy_to_fs + +#if 0 /* Not currently used, but can be enabled as needed */ + + .globl copy_from_gs + .type copy_from_gs, @function +copy_from_gs: + pushw %ds + pushw %gs + popw %ds + call memcpy + popw %ds + ret + .size copy_from_gs, .-copy_from_gs + .globl copy_to_gs + + .type copy_to_gs, @function +copy_to_gs: + pushw %es + pushw %gs + popw %es + call memcpy + popw %es + ret + .size copy_to_gs, .-copy_to_gs + +#endif --- /dev/null +++ b/arch/i386/boot/cpu.c @@ -0,0 +1,69 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/cpucheck.c + * + * Check for obligatory CPU features and abort if the features are not + * present. + */ + +#include "boot.h" +#include "bitops.h" +#include + +static char *cpu_name(int level) +{ + static char buf[6]; + + if (level == 64) { + return "x86-64"; + } else { + sprintf(buf, "i%d86", level); + return buf; + } +} + +int validate_cpu(void) +{ + u32 *err_flags; + int cpu_level, req_level; + + check_cpu(&cpu_level, &req_level, &err_flags); + + if (cpu_level < req_level) { + printf("This kernel requires an %s CPU, ", + cpu_name(req_level)); + printf("but only detected an %s CPU.\n", + cpu_name(cpu_level)); + return -1; + } + + if (err_flags) { + int i, j; + puts("This kernel requires the following features " + "not present on the CPU:\n"); + + for (i = 0; i < NCAPINTS; i++) { + u32 e = err_flags[i]; + + for (j = 0; j < 32; j++) { + if (e & 1) + printf("%d:%d ", i, j); + + e >>= 1; + } + } + putchar('\n'); + return -1; + } else { + return 0; + } +} --- /dev/null +++ b/arch/i386/boot/cpucheck.c @@ -0,0 +1,266 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/cpu.c + * + * Check for obligatory CPU features and abort if the features are not + * present. This code should be compilable as 16-, 32- or 64-bit + * code, so be very careful with types and inline assembly. + * + * This code should not contain any messages; that requires an + * additional wrapper. + * + * As written, this code is not safe for inclusion into the kernel + * proper (after FPU initialization, in particular). + */ + +#ifdef _SETUP +# include "boot.h" +# include "bitops.h" +#endif +#include +#include +#include +#include +#include + +struct cpu_features { + int level; + int model; + u32 flags[NCAPINTS]; +}; + +static struct cpu_features cpu; +static u32 cpu_vendor[3]; +static u32 err_flags[NCAPINTS]; + +#ifdef CONFIG_X86_64 +static const int req_level = 64; +#elif defined(CONFIG_X86_MINIMUM_CPU_MODEL) +static const int req_level = CONFIG_X86_MINIMUM_CPU_MODEL; +#else +static const int req_level = 3; +#endif + +static const u32 req_flags[NCAPINTS] = +{ + REQUIRED_MASK0, + REQUIRED_MASK1, + REQUIRED_MASK2, + REQUIRED_MASK3, + REQUIRED_MASK4, + REQUIRED_MASK5, + REQUIRED_MASK6, +}; + +#define A32(a,b,c,d) (((d) << 24)+((c) << 16)+((b) << 8)+(a)) + +static int is_amd(void) +{ + return cpu_vendor[0] == A32('A','u','t','h') && + cpu_vendor[1] == A32('e','n','t','i') && + cpu_vendor[2] == A32('c','A','M','D'); +} + +static int is_centaur(void) +{ + return cpu_vendor[0] == A32('C','e','n','t') && + cpu_vendor[1] == A32('a','u','r','H') && + cpu_vendor[2] == A32('a','u','l','s'); +} + +static int is_transmeta(void) +{ + return cpu_vendor[0] == A32('G','e','n','u') && + cpu_vendor[1] == A32('i','n','e','T') && + cpu_vendor[2] == A32('M','x','8','6'); +} + +static int has_fpu(void) +{ + u16 fcw = -1, fsw = -1; + u32 cr0; + + asm("movl %%cr0,%0" : "=r" (cr0)); + if (cr0 & (X86_CR0_EM|X86_CR0_TS)) { + cr0 &= ~(X86_CR0_EM|X86_CR0_TS); + asm volatile("movl %0,%%cr0" : : "r" (cr0)); + } + + asm("fninit ; fnstsw %0 ; fnstcw %1" : "+m" (fsw), "+m" (fcw)); + + return fsw == 0 && (fcw & 0x103f) == 0x003f; +} + +static int has_eflag(u32 mask) +{ + u32 f0, f1; + + asm("pushfl ; " + "pushfl ; " + "popl %0 ; " + "movl %0,%1 ; " + "xorl %2,%1 ; " + "pushl %1 ; " + "popfl ; " + "pushfl ; " + "popl %1 ; " + "popfl" + : "=r" (f0), "=r" (f1) + : "g" (mask)); + + return !!((f0^f1) & mask); +} + +static void get_flags(void) +{ + u32 max_intel_level, max_amd_level; + u32 tfms; + + if (has_fpu()) + set_bit(X86_FEATURE_FPU, cpu.flags); + + if (has_eflag(X86_EFLAGS_ID)) { + asm("cpuid" + : "=a" (max_intel_level), + "=b" (cpu_vendor[0]), + "=d" (cpu_vendor[1]), + "=c" (cpu_vendor[2]) + : "a" (0)); + + if (max_intel_level >= 0x00000001 && + max_intel_level <= 0x0000ffff) { + asm("cpuid" + : "=a" (tfms), + "=c" (cpu.flags[4]), + "=d" (cpu.flags[0]) + : "a" (0x00000001) + : "ebx"); + cpu.level = (tfms >> 8) & 15; + cpu.model = (tfms >> 4) & 15; + if (cpu.level >= 6) + cpu.model += ((tfms >> 16) & 0xf) << 4; + } + + asm("cpuid" + : "=a" (max_amd_level) + : "a" (0x80000000) + : "ebx", "ecx", "edx"); + + if (max_amd_level >= 0x80000001 && + max_amd_level <= 0x8000ffff) { + u32 eax = 0x80000001; + asm("cpuid" + : "+a" (eax), + "=c" (cpu.flags[6]), + "=d" (cpu.flags[1]) + : : "ebx"); + } + } +} + +/* Returns a bitmask of which words we have error bits in */ +static int check_flags(void) +{ + u32 err; + int i; + + err = 0; + for (i = 0; i < NCAPINTS; i++) { + err_flags[i] = req_flags[i] & ~cpu.flags[i]; + if (err_flags[i]) + err |= 1 << i; + } + + return err; +} + +/* + * Returns -1 on error. + * + * *cpu_level is set to the current CPU level; *req_level to the required + * level. x86-64 is considered level 64 for this purpose. + * + * *err_flags_ptr is set to the flags error array if there are flags missing. + */ +int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr) +{ + int err; + + memset(&cpu.flags, 0, sizeof cpu.flags); + cpu.level = 3; + + if (has_eflag(X86_EFLAGS_AC)) + cpu.level = 4; + + get_flags(); + err = check_flags(); + + if (test_bit(X86_FEATURE_LM, cpu.flags)) + cpu.level = 64; + + if (err == 0x01 && + !(err_flags[0] & + ~((1 << X86_FEATURE_XMM)|(1 << X86_FEATURE_XMM2))) && + is_amd()) { + /* If this is an AMD and we're only missing SSE+SSE2, try to + turn them on */ + + u32 ecx = MSR_K7_HWCR; + u32 eax, edx; + + asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + eax &= ~(1 << 15); + asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + + get_flags(); /* Make sure it really did something */ + err = check_flags(); + } else if (err == 0x01 && + !(err_flags[0] & ~(1 << X86_FEATURE_CX8)) && + is_centaur() && cpu.model >= 6) { + /* If this is a VIA C3, we might have to enable CX8 + explicitly */ + + u32 ecx = MSR_VIA_FCR; + u32 eax, edx; + + asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + eax |= (1<<1)|(1<<7); + asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + + set_bit(X86_FEATURE_CX8, cpu.flags); + err = check_flags(); + } else if (err == 0x01 && is_transmeta()) { + /* Transmeta might have masked feature bits in word 0 */ + + u32 ecx = 0x80860004; + u32 eax, edx; + u32 level = 1; + + asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx)); + asm("cpuid" + : "+a" (level), "=d" (cpu.flags[0]) + : : "ecx", "ebx"); + asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + + err = check_flags(); + } + + if (err_flags_ptr) + *err_flags_ptr = err ? err_flags : NULL; + if (cpu_level_ptr) + *cpu_level_ptr = cpu.level; + if (req_level_ptr) + *req_level_ptr = req_level; + + return (cpu.level < req_level || err) ? -1 : 0; +} --- a/arch/i386/boot/edd.S +++ /dev/null @@ -1,231 +0,0 @@ -/* - * BIOS Enhanced Disk Drive support - * Copyright (C) 2002, 2003, 2004 Dell, Inc. - * by Matt Domsch October 2002 - * conformant to T13 Committee www.t13.org - * projects 1572D, 1484D, 1386D, 1226DT - * disk signature read by Matt Domsch - * and Andrew Wilks September 2003, June 2004 - * legacy CHS retrieval by Patrick J. LoPresti - * March 2004 - * Command line option parsing, Matt Domsch, November 2004 - */ - -#include -#include - -#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) - -# It is assumed that %ds == INITSEG here - - movb $0, (EDD_MBR_SIG_NR_BUF) - movb $0, (EDDNR) - -# Check the command line for options: -# edd=of disables EDD completely (edd=off) -# edd=sk skips the MBR test (edd=skipmbr) -# edd=on re-enables EDD (edd=on) - - pushl %esi - movw $edd_mbr_sig_start, %di # Default to edd=on - - movl %cs:(cmd_line_ptr), %esi - andl %esi, %esi - jz old_cl # Old boot protocol? - -# Convert to a real-mode pointer in fs:si - movl %esi, %eax - shrl $4, %eax - movw %ax, %fs - andw $0xf, %si - jmp have_cl_pointer - -# Old-style boot protocol? -old_cl: - push %ds # aka INITSEG - pop %fs - - cmpw $0xa33f, (0x20) - jne done_cl # No command line at all? - movw (0x22), %si # Pointer relative to INITSEG - -# fs:si has the pointer to the command line now -have_cl_pointer: - -# Loop through kernel command line one byte at a time. Just in -# case the loader is buggy and failed to null-terminate the command line -# terminate if we get close enough to the end of the segment that we -# cannot fit "edd=XX"... -cl_atspace: - cmpw $-5, %si # Watch for segment wraparound - jae done_cl - movl %fs:(%si), %eax - andb %al, %al # End of line? - jz done_cl - cmpl $EDD_CL_EQUALS, %eax - jz found_edd_equals - cmpb $0x20, %al # <= space consider whitespace - ja cl_skipword - incw %si - jmp cl_atspace - -cl_skipword: - cmpw $-5, %si # Watch for segment wraparound - jae done_cl - movb %fs:(%si), %al # End of string? - andb %al, %al - jz done_cl - cmpb $0x20, %al - jbe cl_atspace - incw %si - jmp cl_skipword - -found_edd_equals: -# only looking at first two characters after equals -# late overrides early on the command line, so keep going after finding something - movw %fs:4(%si), %ax - cmpw $EDD_CL_OFF, %ax # edd=of - je do_edd_off - cmpw $EDD_CL_SKIP, %ax # edd=sk - je do_edd_skipmbr - cmpw $EDD_CL_ON, %ax # edd=on - je do_edd_on - jmp cl_skipword -do_edd_skipmbr: - movw $edd_start, %di - jmp cl_skipword -do_edd_off: - movw $edd_done, %di - jmp cl_skipword -do_edd_on: - movw $edd_mbr_sig_start, %di - jmp cl_skipword - -done_cl: - popl %esi - jmpw *%di - -# Read the first sector of each BIOS disk device and store the 4-byte signature -edd_mbr_sig_start: - movb $0x80, %dl # from device 80 - movw $EDD_MBR_SIG_BUF, %bx # store buffer ptr in bx -edd_mbr_sig_read: - movl $0xFFFFFFFF, %eax - movl %eax, (%bx) # assume failure - pushw %bx - movb $READ_SECTORS, %ah - movb $1, %al # read 1 sector - movb $0, %dh # at head 0 - movw $1, %cx # cylinder 0, sector 0 - pushw %es - pushw %ds - popw %es - movw $EDDBUF, %bx # disk's data goes into EDDBUF - pushw %dx # work around buggy BIOSes - stc # work around buggy BIOSes - int $0x13 - sti # work around buggy BIOSes - popw %dx - popw %es - popw %bx - jc edd_mbr_sig_done # on failure, we're done. - cmpb $0, %ah # some BIOSes do not set CF - jne edd_mbr_sig_done # on failure, we're done. - movl (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR - movl %eax, (%bx) # store success - incb (EDD_MBR_SIG_NR_BUF) # note that we stored something - incb %dl # increment to next device - addw $4, %bx # increment sig buffer ptr - cmpb $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF) # Out of space? - jb edd_mbr_sig_read # keep looping -edd_mbr_sig_done: - -# Do the BIOS Enhanced Disk Drive calls -# This consists of two calls: -# int 13h ah=41h "Check Extensions Present" -# int 13h ah=48h "Get Device Parameters" -# int 13h ah=08h "Legacy Get Device Parameters" -# -# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use -# in the boot_params at EDDBUF. The first four bytes of which are -# used to store the device number, interface support map and version -# results from fn41. The next four bytes are used to store the legacy -# cylinders, heads, and sectors from fn08. The following 74 bytes are used to -# store the results from fn48. Starting from device 80h, fn41, then fn48 -# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE). -# Then the pointer is incremented to store the data for the next call. -# This repeats until either a device doesn't exist, or until EDDMAXNR -# devices have been stored. -# The one tricky part is that ds:si always points EDDEXTSIZE bytes into -# the structure, and the fn41 and fn08 results are stored at offsets -# from there. This removes the need to increment the pointer for -# every store, and leaves it ready for the fn48 call. -# A second one-byte buffer, EDDNR, in the boot_params stores -# the number of BIOS devices which exist, up to EDDMAXNR. -# In setup.c, copy_edd() stores both boot_params buffers away -# for later use, as they would get overwritten otherwise. -# This code is sensitive to the size of the structs in edd.h -edd_start: - # %ds points to the bootsector - # result buffer for fn48 - movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results - # kept just before that - movb $0x80, %dl # BIOS device 0x80 - -edd_check_ext: - movb $CHECKEXTENSIONSPRESENT, %ah # Function 41 - movw $EDDMAGIC1, %bx # magic - int $0x13 # make the call - jc edd_done # no more BIOS devices - - cmpw $EDDMAGIC2, %bx # is magic right? - jne edd_next # nope, next... - - movb %dl, %ds:-8(%si) # store device number - movb %ah, %ds:-7(%si) # store version - movw %cx, %ds:-6(%si) # store extensions - incb (EDDNR) # note that we stored something - -edd_get_device_params: - movw $EDDPARMSIZE, %ds:(%si) # put size - movw $0x0, %ds:2(%si) # work around buggy BIOSes - movb $GETDEVICEPARAMETERS, %ah # Function 48 - int $0x13 # make the call - # Don't check for fail return - # it doesn't matter. -edd_get_legacy_chs: - xorw %ax, %ax - movw %ax, %ds:-4(%si) - movw %ax, %ds:-2(%si) - # Ralf Brown's Interrupt List says to set ES:DI to - # 0000h:0000h "to guard against BIOS bugs" - pushw %es - movw %ax, %es - movw %ax, %di - pushw %dx # legacy call clobbers %dl - movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08 - int $0x13 # make the call - jc edd_legacy_done # failed - movb %cl, %al # Low 6 bits are max - andb $0x3F, %al # sector number - movb %al, %ds:-1(%si) # Record max sect - movb %dh, %ds:-2(%si) # Record max head number - movb %ch, %al # Low 8 bits of max cyl - shr $6, %cl - movb %cl, %ah # High 2 bits of max cyl - movw %ax, %ds:-4(%si) - -edd_legacy_done: - popw %dx - popw %es - movw %si, %ax # increment si - addw $EDDPARMSIZE+EDDEXTSIZE, %ax - movw %ax, %si - -edd_next: - incb %dl # increment to next device - cmpb $EDDMAXNR, (EDDNR) # Out of space? - jb edd_check_ext # keep looping - -edd_done: -#endif --- /dev/null +++ b/arch/i386/boot/edd.c @@ -0,0 +1,196 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/edd.c + * + * Get EDD BIOS disk information + */ + +#include "boot.h" +#include + +#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) + +struct edd_dapa { + u8 pkt_size; + u8 rsvd; + u16 sector_cnt; + u16 buf_off, buf_seg; + u64 lba; + u64 buf_lin_addr; +}; + +/* + * Note: this uses the heap to hold the loaded sector. + */ +static int read_sector(u8 devno, u64 lba, void *buf) +{ + struct edd_dapa dapa; + u16 ax, bx, cx, dx, si; + + memset(&dapa, 0, sizeof dapa); + dapa.pkt_size = sizeof(dapa); + dapa.sector_cnt = 1; + dapa.buf_off = (size_t)buf; + dapa.buf_seg = ds(); + dapa.lba = lba; + + ax = 0x4200; /* Extended Read */ + si = (size_t)&dapa; + dx = devno; + asm("pushfl; stc; int $0x13; setc %%al; popfl" + : "+a" (ax), "+S" (si), "+d" (dx) + : "m" (dapa) + : "ebx", "ecx", "edi", "memory"); + + if (!(u8)ax) + return 0; /* OK */ + + ax = 0x0201; /* Legacy Read, one sector */ + cx = 0x0001; /* Sector 0-0-1 */ + dx = devno; + bx = (size_t)buf; + asm("pushfl; stc; int $0x13; setc %%al; popfl" + : "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx) + : : "esi", "edi", "memory"); + + return -(u8)ax; /* 0 or -1 */ +} + +static u32 read_mbr_sig(u8 devno, struct edd_info *ei) +{ + int sector_size; + char *mbrbuf_ptr, *mbrbuf_end; + u32 mbrsig; + u32 buf_base, mbr_base; + extern char _end[]; + static char mbr_buf[1024]; + + sector_size = ei->params.bytes_per_sector; + if (!sector_size) + sector_size = 512; /* Best available guess */ + + buf_base = (ds() << 4) + (u32)&_end; + mbr_base = (buf_base+sector_size-1) & ~(sector_size-1); + mbrbuf_ptr = mbr_buf + (mbr_base-buf_base); + mbrbuf_end = mbrbuf_ptr + sector_size; + + if (!(boot_params.hdr.loadflags & CAN_USE_HEAP)) + return 0; + if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr) + return 0; + + if (read_sector(devno, 0, mbrbuf_ptr)) + return 0; + + mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET]; + return mbrsig; +} + +static int get_edd_info(u8 devno, struct edd_info *ei) +{ + u16 ax, bx, cx, dx, di; + + memset(ei, 0, sizeof *ei); + + /* Check Extensions Present */ + + ax = 0x4100; + bx = EDDMAGIC1; + dx = devno; + asm("pushfl; stc; int $0x13; setc %%al; popfl" + : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx) + : : "esi", "edi"); + + if ((u8)ax) + return -1; /* No extended information */ + + if (bx != EDDMAGIC2) + return -1; + + ei->device = devno; + ei->version = ax >> 8; /* EDD version number */ + ei->interface_support = cx; /* EDD functionality subsets */ + + /* Extended Get Device Parameters */ + + ei->params.length = sizeof(ei->params); + ax = 0x4800; + dx = devno; + asm("pushfl; int $0x13; popfl" + : "+a" (ax), "+d" (dx) + : "S" (&ei->params) + : "ebx", "ecx", "edi"); + + /* Get legacy CHS parameters */ + + /* Ralf Brown recommends setting ES:DI to 0:0 */ + ax = 0x0800; + dx = devno; + di = 0; + asm("pushw %%es; " + "movw %%di,%%es; " + "pushfl; stc; int $0x13; setc %%al; popfl; " + "popw %%es" + : "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di) + : : "esi"); + + if ((u8)ax == 0) { + ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2); + ei->legacy_max_head = dx >> 8; + ei->legacy_sectors_per_track = cx & 0x3f; + } + + return 0; +} + +void query_edd(void) +{ + char eddarg[8]; + int do_mbr = 1; + int do_edd = 1; + int devno; + struct edd_info ei, *edp; + + if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) { + if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) + do_mbr = 0; + else if (!strcmp(eddarg, "off")) + do_edd = 0; + } + + edp = (struct edd_info *)boot_params.eddbuf; + + if (!do_edd) + return; + + for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) { + /* + * Scan the BIOS-supported hard disks and query EDD + * information... + */ + get_edd_info(devno, &ei); + + if (boot_params.eddbuf_entries < EDDMAXNR) { + memcpy(edp, &ei, sizeof ei); + edp++; + boot_params.eddbuf_entries++; + } + + if (do_mbr) { + u32 mbr_sig; + mbr_sig = read_mbr_sig(devno, &ei); + boot_params.edd_mbr_sig_buffer[devno-0x80] = mbr_sig; + } + } +} + +#endif --- /dev/null +++ b/arch/i386/boot/header.S @@ -0,0 +1,283 @@ +/* + * header.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Based on bootsect.S and setup.S + * modified by more people than can be counted + * + * Rewritten as a common file by H. Peter Anvin (Apr 2007) + * + * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment + * addresses must be multiplied by 16 to obtain their respective linear + * addresses. To avoid confusion, linear addresses are written using leading + * hex while segment addresses are written as segment:offset. + * + */ + +#include +#include +#include +#include +#include +#include +#include "boot.h" + +SETUPSECTS = 4 /* default nr of setup-sectors */ +BOOTSEG = 0x07C0 /* original address of boot-sector */ +SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */ +SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */ + /* to be loaded */ +ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */ +SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */ + +#ifndef SVGA_MODE +#define SVGA_MODE ASK_VGA +#endif + +#ifndef RAMDISK +#define RAMDISK 0 +#endif + +#ifndef ROOT_RDONLY +#define ROOT_RDONLY 1 +#endif + + .code16 + .section ".bstext", "ax" + + .global bootsect_start +bootsect_start: + + # Normalize the start address + ljmp $BOOTSEG, $start2 + +start2: + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + xorw %sp, %sp + sti + cld + + movw $bugger_off_msg, %si + +msg_loop: + lodsb + andb %al, %al + jz bs_die + movb $0xe, %ah + movw $7, %bx + int $0x10 + jmp msg_loop + +bs_die: + # Allow the user to press a key, then reboot + xorw %ax, %ax + int $0x16 + int $0x19 + + # int 0x19 should never return. In case it does anyway, + # invoke the BIOS reset code... + ljmp $0xf000,$0xfff0 + + .section ".bsdata", "a" +bugger_off_msg: + .ascii "Direct booting from floppy is no longer supported.\r\n" + .ascii "Please use a boot loader program instead.\r\n" + .ascii "\n" + .ascii "Remove disk and press any key to reboot . . .\r\n" + .byte 0 + + + # Kernel attributes; used by setup. This is part 1 of the + # header, from the old boot sector. + + .section ".header", "a" + .globl hdr +hdr: +setup_sects: .byte SETUPSECTS +root_flags: .word ROOT_RDONLY +syssize: .long SYSSIZE +ram_size: .word RAMDISK +vid_mode: .word SVGA_MODE +root_dev: .word ROOT_DEV +boot_flag: .word 0xAA55 + + # offset 512, entry point + + .globl _start +_start: + # Explicitly enter this as bytes, or the assembler + # tries to generate a 3-byte jump here, which causes + # everything else to push off to the wrong offset. + .byte 0xeb # short (2-byte) jump + .byte start_of_setup-1f +1: + + # Part 2 of the header, from the old setup.S + + .ascii "HdrS" # header signature + .word 0x0206 # header version number (>= 0x0105) + # or else old loadlin-1.5 will fail) + .globl realmode_swtch +realmode_swtch: .word 0, 0 # default_switch, SETUPSEG +start_sys_seg: .word SYSSEG + .word kernel_version-512 # pointing to kernel version string + # above section of header is compatible + # with loadlin-1.5 (header v1.5). Don't + # change it. + +type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, + # Bootlin, SYSLX, bootsect...) + # See Documentation/i386/boot.txt for + # assigned ids + +# flags, unused bits must be zero (RFU) bit within loadflags +loadflags: +LOADED_HIGH = 1 # If set, the kernel is loaded high +CAN_USE_HEAP = 0x80 # If set, the loader also has set + # heap_end_ptr to tell how much + # space behind setup.S can be used for + # heap purposes. + # Only the loader knows what is free +#ifndef __BIG_KERNEL__ + .byte 0 +#else + .byte LOADED_HIGH +#endif + +setup_move_size: .word 0x8000 # size to move, when setup is not + # loaded at 0x90000. We will move setup + # to 0x90000 then just before jumping + # into the kernel. However, only the + # loader knows how much data behind + # us also needs to be loaded. + +code32_start: # here loaders can put a different + # start address for 32-bit code. +#ifndef __BIG_KERNEL__ + .long 0x1000 # 0x1000 = default for zImage +#else + .long 0x100000 # 0x100000 = default for big kernel +#endif + +ramdisk_image: .long 0 # address of loaded ramdisk image + # Here the loader puts the 32-bit + # address where it loaded the image. + # This only will be read by the kernel. + +ramdisk_size: .long 0 # its size in bytes + +bootsect_kludge: + .long 0 # obsolete + +heap_end_ptr: .word _end+1024 # (Header version 0x0201 or later) + # space from here (exclusive) down to + # end of setup code can be used by setup + # for local heap purposes. + +pad1: .word 0 +cmd_line_ptr: .long 0 # (Header version 0x0202 or later) + # If nonzero, a 32-bit pointer + # to the kernel command line. + # The command line should be + # located between the start of + # setup and the end of low + # memory (0xa0000), or it may + # get overwritten before it + # gets read. If this field is + # used, there is no longer + # anything magical about the + # 0x90000 segment; the setup + # can be located anywhere in + # low memory 0x10000 or higher. + +ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff + # (Header version 0x0203 or later) + # The highest safe address for + # the contents of an initrd + +kernel_alignment: .long CONFIG_PHYSICAL_ALIGN #physical addr alignment + #required for protected mode + #kernel +#ifdef CONFIG_RELOCATABLE +relocatable_kernel: .byte 1 +#else +relocatable_kernel: .byte 0 +#endif +pad2: .byte 0 +pad3: .word 0 + +cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, + #added with boot protocol + #version 2.06 + +# End of setup header ##################################################### + + .section ".inittext", "ax" +start_of_setup: +#ifdef SAFE_RESET_DISK_CONTROLLER +# Reset the disk controller. + movw $0x0000, %ax # Reset disk controller + movb $0x80, %dl # All disks + int $0x13 +#endif + +# We will have entired with %cs = %ds+0x20, normalize %cs so +# it is on par with the other segments. + pushw %ds + pushw $setup2 + lretw + +setup2: +# Force %es = %ds + movw %ds, %ax + movw %ax, %es + cld + +# Stack paranoia: align the stack and make sure it is good +# for both 16- and 32-bit references. In particular, if we +# were meant to have been using the full 16-bit segment, the +# caller might have set %sp to zero, which breaks %esp-based +# references. + andw $~3, %sp # dword align (might as well...) + jnz 1f + movw $0xfffc, %sp # Make sure we're not zero +1: movzwl %sp, %esp # Clear upper half of %esp + sti + +# Check signature at end of setup + cmpl $0x5a5aaa55, setup_sig + jne setup_bad + +# Zero the bss + movw $__bss_start, %di + movw $_end+3, %cx + xorl %eax, %eax + subw %di, %cx + shrw $2, %cx + rep; stosl + +# Jump to C code (should not return) + calll main + +# Setup corrupt somehow... +setup_bad: + movl $setup_corrupt, %eax + calll puts + # Fall through... + + .globl die + .type die, @function +die: + hlt + jmp die + + .size die, .-due + + .section ".initdata", "a" +setup_corrupt: + .byte 7 + .string "No setup signature found..." --- /dev/null +++ b/arch/i386/boot/main.c @@ -0,0 +1,161 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/main.c + * + * Main module for the real-mode kernel code + */ + +#include "boot.h" + +struct boot_params boot_params __attribute__((aligned(16))); + +char *HEAP = _end; +char *heap_end = _end; /* Default end of heap = no heap */ + +/* + * Copy the header into the boot parameter block. Since this + * screws up the old-style command line protocol, adjust by + * filling in the new-style command line pointer instead. + */ +#define OLD_CL_MAGIC 0xA33F +#define OLD_CL_ADDRESS 0x20 + +static void copy_boot_params(void) +{ + struct old_cmdline { + u16 cl_magic; + u16 cl_offset; + }; + const struct old_cmdline * const oldcmd = + (const struct old_cmdline *)OLD_CL_ADDRESS; + + BUILD_BUG_ON(sizeof boot_params != 4096); + memcpy(&boot_params.hdr, &hdr, sizeof hdr); + + if (!boot_params.hdr.cmd_line_ptr && + oldcmd->cl_magic == OLD_CL_MAGIC) { + /* Old-style command line protocol. */ + u16 cmdline_seg; + + /* Figure out if the command line falls in the region + of memory that an old kernel would have copied up + to 0x90000... */ + if (oldcmd->cl_offset < boot_params.hdr.setup_move_size) + cmdline_seg = ds(); + else + cmdline_seg = 0x9000; + + boot_params.hdr.cmd_line_ptr = + (cmdline_seg << 4) + oldcmd->cl_offset; + } +} + +/* + * Set the keyboard repeat rate to maximum. Unclear why this + * is done here; this might be possible to kill off as stale code. + */ +static void keyboard_set_repeat(void) +{ + u16 ax = 0x0305; + u16 bx = 0; + asm volatile("int $0x16" + : "+a" (ax), "+b" (bx) + : : "ecx", "edx", "esi", "edi"); +} + +/* + * Get Intel SpeedStep IST information. + */ +static void query_speedstep_ist(void) +{ + asm("int $0x15" + : "=a" (boot_params.speedstep_info[0]), + "=b" (boot_params.speedstep_info[1]), + "=c" (boot_params.speedstep_info[2]), + "=d" (boot_params.speedstep_info[3]) + : "a" (0x0000e980), /* IST Support */ + "d" (0x47534943)); /* Request value */ +} + +/* + * Tell the BIOS what CPU mode we intend to run in. + */ +static void set_bios_mode(void) +{ +#ifdef CONFIG_X86_64 + u32 eax, ebx; + + eax = 0xec00; + ebx = 2; + asm volatile("int $0x15" + : "+a" (eax), "+b" (ebx) + : : "ecx", "edx", "esi", "edi"); +#endif +} + +void main(void) +{ + /* First, copy the boot header into the "zeropage" */ + copy_boot_params(); + + /* End of heap check */ + if (boot_params.hdr.loadflags & CAN_USE_HEAP) { + heap_end = (char *)(boot_params.hdr.heap_end_ptr + +0x200-STACK_SIZE); + } else { + /* Boot protocol 2.00 only, no heap available */ + puts("WARNING: Ancient bootloader, some functionality " + "may be limited!\n"); + } + + /* Make sure we have all the proper CPU support */ + if (validate_cpu()) { + puts("Unable to boot - please use a kernel appropriate " + "for your CPU.\n"); + die(); + } + + /* Tell the BIOS what CPU mode we intend to run in. */ + set_bios_mode(); + + /* Detect memory layout */ + detect_memory(); + + /* Set keyboard repeat rate (why?) */ + keyboard_set_repeat(); + + /* Set the video mode */ + set_video(); + + /* Query MCA information */ + query_mca(); + + /* Voyager */ +#ifdef CONFIG_X86_VOYAGER + query_voyager(); +#endif + + /* Query SpeedStep IST information */ + query_speedstep_ist(); + + /* Query APM information */ +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) + query_apm_bios(); +#endif + + /* Query EDD information */ +#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) + query_edd(); +#endif + /* Do the last things and invoke protected mode */ + go_to_protected_mode(); +} --- /dev/null +++ b/arch/i386/boot/mca.c @@ -0,0 +1,43 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/mca.c + * + * Get the MCA system description table + */ + +#include "boot.h" + +int query_mca(void) +{ + u8 err; + u16 es, bx, len; + + asm("pushw %%es ; " + "int $0x15 ; " + "setc %0 ; " + "movw %%es, %1 ; " + "popw %%es" + : "=acdSDm" (err), "=acdSDm" (es), "=b" (bx) + : "a" (0xc000)); + + if (err) + return -1; /* No MCA present */ + + set_fs(es); + len = rdfs16(bx); + + if (len > sizeof(boot_params.sys_desc_table)) + len = sizeof(boot_params.sys_desc_table); + + copy_from_fs(&boot_params.sys_desc_table, bx, len); + return 0; +} --- /dev/null +++ b/arch/i386/boot/memory.c @@ -0,0 +1,99 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/memory.c + * + * Memory detection code + */ + +#include "boot.h" + +#define SMAP 0x534d4150 /* ASCII "SMAP" */ + +static int detect_memory_e820(void) +{ + u32 next = 0; + u32 size, id; + u8 err; + struct e820entry *desc = boot_params.e820_map; + + do { + size = sizeof(struct e820entry); + id = SMAP; + asm("int $0x15; setc %0" + : "=am" (err), "+b" (next), "+d" (id), "+c" (size), + "=m" (*desc) + : "D" (desc), "a" (0xe820)); + + if (err || id != SMAP) + break; + + boot_params.e820_entries++; + desc++; + } while (next && boot_params.e820_entries < E820MAX); + + return boot_params.e820_entries; +} + +static int detect_memory_e801(void) +{ + u16 ax, bx, cx, dx; + u8 err; + + bx = cx = dx = 0; + ax = 0xe801; + asm("stc; int $0x15; setc %0" + : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx)); + + if (err) + return -1; + + /* Do we really need to do this? */ + if (cx || dx) { + ax = cx; + bx = dx; + } + + if (ax > 15*1024) + return -1; /* Bogus! */ + + /* This ignores memory above 16MB if we have a memory hole + there. If someone actually finds a machine with a memory + hole at 16MB and no support for 0E820h they should probably + generate a fake e820 map. */ + boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax; + + return 0; +} + +static int detect_memory_88(void) +{ + u16 ax; + u8 err; + + ax = 0x8800; + asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); + + boot_params.screen_info.ext_mem_k = ax; + + return -err; +} + +int detect_memory(void) +{ + if (detect_memory_e820() > 0) + return 0; + + if (!detect_memory_e801()) + return 0; + + return detect_memory_88(); +} --- /dev/null +++ b/arch/i386/boot/pm.c @@ -0,0 +1,170 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/pm.c + * + * Prepare the machine for transition to protected mode. + */ + +#include "boot.h" +#include + +/* + * Invoke the realmode switch hook if present; otherwise + * disable all interrupts. + */ +static void realmode_switch_hook(void) +{ + if (boot_params.hdr.realmode_swtch) { + asm volatile("lcallw *%0" + : : "m" (boot_params.hdr.realmode_swtch) + : "eax", "ebx", "ecx", "edx"); + } else { + asm volatile("cli"); + outb(0x80, 0x70); /* Disable NMI */ + io_delay(); + } +} + +/* + * A zImage kernel is loaded at 0x10000 but wants to run at 0x1000. + * A bzImage kernel is loaded and runs at 0x100000. + */ +static void move_kernel_around(void) +{ + /* Note: rely on the compile-time option here rather than + the LOADED_HIGH flag. The Qemu kernel loader unconditionally + sets the loadflags to zero. */ +#ifndef __BIG_KERNEL__ + u16 dst_seg, src_seg; + u32 syssize; + + dst_seg = 0x1000 >> 4; + src_seg = 0x10000 >> 4; + syssize = boot_params.hdr.syssize; /* Size in 16-byte paragraps */ + + while (syssize) { + int paras = (syssize >= 0x1000) ? 0x1000 : syssize; + int dwords = paras << 2; + + asm volatile("pushw %%es ; " + "pushw %%ds ; " + "movw %1,%%es ; " + "movw %2,%%ds ; " + "xorw %%di,%%di ; " + "xorw %%si,%%si ; " + "rep;movsl ; " + "popw %%ds ; " + "popw %%es" + : "+c" (dwords) + : "rm" (dst_seg), "rm" (src_seg) + : "esi", "edi"); + + syssize -= paras; + dst_seg += paras; + src_seg += paras; + } +#endif +} + +/* + * Disable all interrupts at the legacy PIC. + */ +static void mask_all_interrupts(void) +{ + outb(0xff, 0xa1); /* Mask all interrupts on the seconday PIC */ + io_delay(); + outb(0xfb, 0x21); /* Mask all but cascade on the primary PIC */ + io_delay(); +} + +/* + * Reset IGNNE# if asserted in the FPU. + */ +static void reset_coprocessor(void) +{ + outb(0, 0xf0); + io_delay(); + outb(0, 0xf1); + io_delay(); +} + +/* + * Set up the GDT + */ +#define GDT_ENTRY(flags,base,limit) \ + (((u64)(base & 0xff000000) << 32) | \ + ((u64)flags << 40) | \ + ((u64)(limit & 0x00ff0000) << 32) | \ + ((u64)(base & 0x00ffff00) << 16) | \ + ((u64)(limit & 0x0000ffff))) + +struct gdt_ptr { + u16 len; + u32 ptr; +} __attribute__((packed)); + +static void setup_gdt(void) +{ + /* There are machines which are known to not boot with the GDT + being 8-byte unaligned. Intel recommends 16 byte alignment. */ + static const u64 boot_gdt[] __attribute__((aligned(16))) = { + /* CS: code, read/execute, 4 GB, base 0 */ + [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), + /* DS: data, read/write, 4 GB, base 0 */ + [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), + }; + struct gdt_ptr gdt; + + gdt.len = sizeof(boot_gdt)-1; + gdt.ptr = (u32)&boot_gdt + (ds() << 4); + + asm volatile("lgdtl %0" : : "m" (gdt)); +} + +/* + * Set up the IDT + */ +static void setup_idt(void) +{ + static const struct gdt_ptr null_idt = {0, 0}; + asm volatile("lidtl %0" : : "m" (null_idt)); +} + +/* + * Actual invocation sequence + */ +void go_to_protected_mode(void) +{ + /* Hook before leaving real mode, also disables interrupts */ + realmode_switch_hook(); + + /* Move the kernel/setup to their final resting places */ + move_kernel_around(); + + /* Enable the A20 gate */ + if (enable_a20()) { + puts("A20 gate not responding, unable to boot...\n"); + die(); + } + + /* Reset coprocessor (IGNNE#) */ + reset_coprocessor(); + + /* Mask all interrupts in the PIC */ + mask_all_interrupts(); + + /* Actual transition to protected mode... */ + setup_idt(); + setup_gdt(); + protected_mode_jump(boot_params.hdr.code32_start, + (u32)&boot_params + (ds() << 4)); +} --- /dev/null +++ b/arch/i386/boot/pmjump.S @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/pmjump.S + * + * The actual transition into protected mode + */ + +#include +#include + + .text + + .globl protected_mode_jump + .type protected_mode_jump, @function + + .code16 + +/* + * void protected_mode_jump(u32 entrypoint, u32 bootparams); + */ +protected_mode_jump: + xorl %ebx, %ebx # Flag to indicate this is a boot + movl %edx, %esi # Pointer to boot_params table + movl %eax, 2f # Patch ljmpl instruction + jmp 1f # Short jump to flush instruction q. + +1: + movw $__BOOT_DS, %cx + + movl %cr0, %edx + orb $1, %dl # Protected mode (PE) bit + movl %edx, %cr0 + + movw %cx, %ds + movw %cx, %es + movw %cx, %fs + movw %cx, %gs + movw %cx, %ss + + # Jump to the 32-bit entrypoint + .byte 0x66, 0xea # ljmpl opcode +2: .long 0 # offset + .word __BOOT_CS # segment + + .size protected_mode_jump, .-protected_mode_jump --- /dev/null +++ b/arch/i386/boot/printf.c @@ -0,0 +1,331 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/printf.c + * + * Oh, it's a waste of space, but oh-so-yummy for debugging. This + * version of printf() does not include 64-bit support. "Live with + * it." + * + */ + +#include "boot.h" + +static inline int isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +static int skip_atoi(const char **s) +{ + int i = 0; + + while (isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +unsigned int atou(const char *s) +{ + unsigned int i = 0; + while (isdigit(*s)) + i = i * 10 + (*s++ - '0'); + return i; +} + +static int strnlen(const char *s, int maxlen) +{ + const char *es = s; + while (*es && maxlen) { + es++; + maxlen--; + } + + return (es - s); +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char *number(char *str, long num, int base, int size, int precision, + int type) +{ + char c, sign, tmp[66]; + const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++] = '0'; + else + while (num != 0) + tmp[i++] = digits[do_div(num, base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base == 8) + *str++ = '0'; + else if (base == 16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char *str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str = buf; *fmt; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + case 'n': + if (qualifier == 'l') { + long *ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int *ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short)va_arg(args, int); + if (flags & SIGN) + num = (short)num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str - buf; +} + +int sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + return i; +} + +int printf(const char *fmt, ...) +{ + char printf_buf[1024]; + va_list args; + int printed; + + va_start(args, fmt); + printed = vsprintf(printf_buf, fmt, args); + va_end(args); + + puts(printf_buf); + + return printed; +} --- a/arch/i386/boot/setup.S +++ /dev/null @@ -1,1075 +0,0 @@ -/* - * setup.S Copyright (C) 1991, 1992 Linus Torvalds - * - * setup.s is responsible for getting the system data from the BIOS, - * and putting them into the appropriate places in system memory. - * both setup.s and system has been loaded by the bootblock. - * - * This code asks the bios for memory/disk/other parameters, and - * puts them in a "safe" place: 0x90000-0x901FF, ie where the - * boot-block used to be. It is then up to the protected mode - * system to read them from there before the area is overwritten - * for buffer-blocks. - * - * Move PS/2 aux init code to psaux.c - * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 - * - * some changes and additional features by Christoph Niemann, - * March 1993/June 1994 (Christoph.Niemann@linux.org) - * - * add APM BIOS checking by Stephen Rothwell, May 1994 - * (sfr@canb.auug.org.au) - * - * High load stuff, initrd support and position independency - * by Hans Lermen & Werner Almesberger, February 1996 - * , - * - * Video handling moved to video.S by Martin Mares, March 1996 - * - * - * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david - * parsons) to avoid loadlin confusion, July 1997 - * - * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. - * - * - * Fix to work around buggy BIOSes which don't use carry bit correctly - * and/or report extended memory in CX/DX for e801h memory size detection - * call. As a result the kernel got wrong figures. The int15/e801h docs - * from Ralf Brown interrupt list seem to indicate AX/BX should be used - * anyway. So to avoid breaking many machines (presumably there was a reason - * to orginally use CX/DX instead of AX/BX), we do a kludge to see - * if CX/DX have been changed in the e801 call and if so use AX/BX . - * Michael Miller, April 2001 - * - * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes - * by Robert Schwebel, December 2001 - */ - -#include -#include -#include -#include -#include -#include -#include - -/* Signature words to ensure LILO loaded us right */ -#define SIG1 0xAA55 -#define SIG2 0x5A5A - -INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way -SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). -SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment - # ... and the former contents of CS - -DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020 - -.code16 -.globl begtext, begdata, begbss, endtext, enddata, endbss - -.text -begtext: -.data -begdata: -.bss -begbss: -.text - -start: - jmp trampoline - -# This is the setup header, and it must start at %cs:2 (old 0x9020:2) - - .ascii "HdrS" # header signature - .word 0x0206 # header version number (>= 0x0105) - # or else old loadlin-1.5 will fail) -realmode_swtch: .word 0, 0 # default_switch, SETUPSEG -start_sys_seg: .word SYSSEG - .word kernel_version # pointing to kernel version string - # above section of header is compatible - # with loadlin-1.5 (header v1.5). Don't - # change it. - -type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, - # Bootlin, SYSLX, bootsect...) - # See Documentation/i386/boot.txt for - # assigned ids - -# flags, unused bits must be zero (RFU) bit within loadflags -loadflags: -LOADED_HIGH = 1 # If set, the kernel is loaded high -CAN_USE_HEAP = 0x80 # If set, the loader also has set - # heap_end_ptr to tell how much - # space behind setup.S can be used for - # heap purposes. - # Only the loader knows what is free -#ifndef __BIG_KERNEL__ - .byte 0 -#else - .byte LOADED_HIGH -#endif - -setup_move_size: .word 0x8000 # size to move, when setup is not - # loaded at 0x90000. We will move setup - # to 0x90000 then just before jumping - # into the kernel. However, only the - # loader knows how much data behind - # us also needs to be loaded. - -code32_start: # here loaders can put a different - # start address for 32-bit code. -#ifndef __BIG_KERNEL__ - .long 0x1000 # 0x1000 = default for zImage -#else - .long 0x100000 # 0x100000 = default for big kernel -#endif - -ramdisk_image: .long 0 # address of loaded ramdisk image - # Here the loader puts the 32-bit - # address where it loaded the image. - # This only will be read by the kernel. - -ramdisk_size: .long 0 # its size in bytes - -bootsect_kludge: - .long 0 # obsolete - -heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later) - # space from here (exclusive) down to - # end of setup code can be used by setup - # for local heap purposes. - -pad1: .word 0 -cmd_line_ptr: .long 0 # (Header version 0x0202 or later) - # If nonzero, a 32-bit pointer - # to the kernel command line. - # The command line should be - # located between the start of - # setup and the end of low - # memory (0xa0000), or it may - # get overwritten before it - # gets read. If this field is - # used, there is no longer - # anything magical about the - # 0x90000 segment; the setup - # can be located anywhere in - # low memory 0x10000 or higher. - -ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff - # (Header version 0x0203 or later) - # The highest safe address for - # the contents of an initrd - -kernel_alignment: .long CONFIG_PHYSICAL_ALIGN #physical addr alignment - #required for protected mode - #kernel -#ifdef CONFIG_RELOCATABLE -relocatable_kernel: .byte 1 -#else -relocatable_kernel: .byte 0 -#endif -pad2: .byte 0 -pad3: .word 0 - -cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, - #added with boot protocol - #version 2.06 - -trampoline: call start_of_setup - .align 16 - # The offset at this point is 0x240 - .space (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff) -# End of setup header ##################################################### - -start_of_setup: -# Bootlin depends on this being done early - movw $0x01500, %ax - movb $0x81, %dl - int $0x13 - -#ifdef SAFE_RESET_DISK_CONTROLLER -# Reset the disk controller. - movw $0x0000, %ax - movb $0x80, %dl - int $0x13 -#endif - -# Set %ds = %cs, we know that SETUPSEG = %cs at this point - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds -# Check signature at end of setup - cmpw $SIG1, setup_sig1 - jne bad_sig - - cmpw $SIG2, setup_sig2 - jne bad_sig - - jmp good_sig1 - -# Routine to print asciiz string at ds:si -prtstr: - lodsb - andb %al, %al - jz fin - - call prtchr - jmp prtstr - -fin: ret - -# Space printing -prtsp2: call prtspc # Print double space -prtspc: movb $0x20, %al # Print single space (note: fall-thru) - -# Part of above routine, this one just prints ascii al -prtchr: pushw %ax - pushw %cx - movw $7,%bx - movw $0x01, %cx - movb $0x0e, %ah - int $0x10 - popw %cx - popw %ax - ret - -beep: movb $0x07, %al - jmp prtchr - -no_sig_mess: .string "No setup signature found ..." - -good_sig1: - jmp good_sig - -# We now have to find the rest of the setup code/data -bad_sig: - movw %cs, %ax # SETUPSEG - subw $DELTA_INITSEG, %ax # INITSEG - movw %ax, %ds - xorb %bh, %bh - movb (497), %bl # get setup sect from bootsect - subw $4, %bx # LILO loads 4 sectors of setup - shlw $8, %bx # convert to words (1sect=2^8 words) - movw %bx, %cx - shrw $3, %bx # convert to segment - addw $SYSSEG, %bx - movw %bx, %cs:start_sys_seg -# Move rest of setup code/data to here - movw $2048, %di # four sectors loaded by LILO - subw %si, %si - pushw %cs - popw %es - movw $SYSSEG, %ax - movw %ax, %ds - rep - movsw - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds - cmpw $SIG1, setup_sig1 - jne no_sig - - cmpw $SIG2, setup_sig2 - jne no_sig - - jmp good_sig - -no_sig: - lea no_sig_mess, %si - call prtstr - -no_sig_loop: - hlt - jmp no_sig_loop - -good_sig: - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %ds -# Check if an old loader tries to load a big-kernel - testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel? - jz loader_ok # No, no danger for old loaders. - - cmpb $0, %cs:type_of_loader # Do we have a loader that - # can deal with us? - jnz loader_ok # Yes, continue. - - pushw %cs # No, we have an old loader, - popw %ds # die. - lea loader_panic_mess, %si - call prtstr - - jmp no_sig_loop - -loader_panic_mess: .string "Wrong loader, giving up..." - -# check minimum cpuid -# we do this here because it is the last place we can actually -# show a user visible error message. Later the video modus -# might be already messed up. -loader_ok: - call verify_cpu - testl %eax,%eax - jz cpu_ok - movw %cs,%ax # aka SETUPSEG - movw %ax,%ds - lea cpu_panic_mess,%si - call prtstr -1: jmp 1b - -cpu_panic_mess: - .asciz "PANIC: CPU too old for this kernel." - -#include "../kernel/verify_cpu.S" - -cpu_ok: -# Get memory size (extended mem, kB) - - xorl %eax, %eax - movl %eax, (0x1e0) -#ifndef STANDARD_MEMORY_BIOS_CALL - movb %al, (E820NR) -# Try three different memory detection schemes. First, try -# e820h, which lets us assemble a memory map, then try e801h, -# which returns a 32-bit memory size, and finally 88h, which -# returns 0-64m - -# method E820H: -# the memory map from hell. e820h returns memory classified into -# a whole bunch of different types, and allows memory holes and -# everything. We scan through this memory map and build a list -# of the first 32 memory areas, which we return at [E820MAP]. -# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification. - -#define SMAP 0x534d4150 - -meme820: - xorl %ebx, %ebx # continuation counter - movw $E820MAP, %di # point into the whitelist - # so we can have the bios - # directly write into it. - -jmpe820: - movl $0x0000e820, %eax # e820, upper word zeroed - movl $SMAP, %edx # ascii 'SMAP' - movl $20, %ecx # size of the e820rec - pushw %ds # data record. - popw %es - int $0x15 # make the call - jc bail820 # fall to e801 if it fails - - cmpl $SMAP, %eax # check the return is `SMAP' - jne bail820 # fall to e801 if it fails - -# cmpl $1, 16(%di) # is this usable memory? -# jne again820 - - # If this is usable memory, we save it by simply advancing %di by - # sizeof(e820rec). - # -good820: - movb (E820NR), %al # up to 128 entries - cmpb $E820MAX, %al - jae bail820 - - incb (E820NR) - movw %di, %ax - addw $20, %ax - movw %ax, %di -again820: - cmpl $0, %ebx # check to see if - jne jmpe820 # %ebx is set to EOF -bail820: - - -# method E801H: -# memory size is in 1k chunksizes, to avoid confusing loadlin. -# we store the 0xe801 memory size in a completely different place, -# because it will most likely be longer than 16 bits. -# (use 1e0 because that's what Larry Augustine uses in his -# alternative new memory detection scheme, and it's sensible -# to write everything into the same place.) - -meme801: - stc # fix to work around buggy - xorw %cx,%cx # BIOSes which don't clear/set - xorw %dx,%dx # carry on pass/error of - # e801h memory size call - # or merely pass cx,dx though - # without changing them. - movw $0xe801, %ax - int $0x15 - jc mem88 - - cmpw $0x0, %cx # Kludge to handle BIOSes - jne e801usecxdx # which report their extended - cmpw $0x0, %dx # memory in AX/BX rather than - jne e801usecxdx # CX/DX. The spec I have read - movw %ax, %cx # seems to indicate AX/BX - movw %bx, %dx # are more reasonable anyway... - -e801usecxdx: - andl $0xffff, %edx # clear sign extend - shll $6, %edx # and go from 64k to 1k chunks - movl %edx, (0x1e0) # store extended memory size - andl $0xffff, %ecx # clear sign extend - addl %ecx, (0x1e0) # and add lower memory into - # total size. - -# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or -# 64mb, depending on the bios) in ax. -mem88: - -#endif - movb $0x88, %ah - int $0x15 - movw %ax, (2) - -# Set the keyboard repeat rate to the max - movw $0x0305, %ax - xorw %bx, %bx - int $0x16 - -# Check for video adapter and its parameters and allow the -# user to browse video modes. - call video # NOTE: we need %ds pointing - # to bootsector - -# Get hd0 data... - xorw %ax, %ax - movw %ax, %ds - ldsw (4 * 0x41), %si - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - pushw %ax - movw %ax, %es - movw $0x0080, %di - movw $0x10, %cx - pushw %cx - cld - rep - movsb -# Get hd1 data... - xorw %ax, %ax - movw %ax, %ds - ldsw (4 * 0x46), %si - popw %cx - popw %es - movw $0x0090, %di - rep - movsb -# Check that there IS a hd1 :-) - movw $0x01500, %ax - movb $0x81, %dl - int $0x13 - jc no_disk1 - - cmpb $3, %ah - je is_disk1 - -no_disk1: - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %es - movw $0x0090, %di - movw $0x10, %cx - xorw %ax, %ax - cld - rep - stosb -is_disk1: -# check for Micro Channel (MCA) bus - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %ds - xorw %ax, %ax - movw %ax, (0xa0) # set table length to 0 - movb $0xc0, %ah - stc - int $0x15 # moves feature table to es:bx - jc no_mca - - pushw %ds - movw %es, %ax - movw %ax, %ds - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %es - movw %bx, %si - movw $0xa0, %di - movw (%si), %cx - addw $2, %cx # table length is a short - cmpw $0x10, %cx - jc sysdesc_ok - - movw $0x10, %cx # we keep only first 16 bytes -sysdesc_ok: - rep - movsb - popw %ds -no_mca: -#ifdef CONFIG_X86_VOYAGER - movb $0xff, 0x40 # flag on config found - movb $0xc0, %al - mov $0xff, %ah - int $0x15 # put voyager config info at es:di - jc no_voyager - movw $0x40, %si # place voyager info in apm table - cld - movw $7, %cx -voyager_rep: - movb %es:(%di), %al - movb %al,(%si) - incw %di - incw %si - decw %cx - jnz voyager_rep -no_voyager: -#endif -# Check for PS/2 pointing device - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %ds - movb $0, (0x1ff) # default is no pointing device - int $0x11 # int 0x11: equipment list - testb $0x04, %al # check if mouse installed - jz no_psmouse - - movb $0xAA, (0x1ff) # device present -no_psmouse: - -#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) - movl $0x0000E980, %eax # IST Support - movl $0x47534943, %edx # Request value - int $0x15 - - movl %eax, (96) - movl %ebx, (100) - movl %ecx, (104) - movl %edx, (108) -#endif - -#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) -# Then check for an APM BIOS... - # %ds points to the bootsector - movw $0, 0x40 # version = 0 means no APM BIOS - movw $0x05300, %ax # APM BIOS installation check - xorw %bx, %bx - int $0x15 - jc done_apm_bios # Nope, no APM BIOS - - cmpw $0x0504d, %bx # Check for "PM" signature - jne done_apm_bios # No signature, no APM BIOS - - andw $0x02, %cx # Is 32 bit supported? - je done_apm_bios # No 32-bit, no (good) APM BIOS - - movw $0x05304, %ax # Disconnect first just in case - xorw %bx, %bx - int $0x15 # ignore return code - movw $0x05303, %ax # 32 bit connect - xorl %ebx, %ebx - xorw %cx, %cx # paranoia :-) - xorw %dx, %dx # ... - xorl %esi, %esi # ... - xorw %di, %di # ... - int $0x15 - jc no_32_apm_bios # Ack, error. - - movw %ax, (66) # BIOS code segment - movl %ebx, (68) # BIOS entry point offset - movw %cx, (72) # BIOS 16 bit code segment - movw %dx, (74) # BIOS data segment - movl %esi, (78) # BIOS code segment lengths - movw %di, (82) # BIOS data segment length -# Redo the installation check as the 32 bit connect -# modifies the flags returned on some BIOSs - movw $0x05300, %ax # APM BIOS installation check - xorw %bx, %bx - xorw %cx, %cx # paranoia - int $0x15 - jc apm_disconnect # error -> shouldn't happen - - cmpw $0x0504d, %bx # check for "PM" signature - jne apm_disconnect # no sig -> shouldn't happen - - movw %ax, (64) # record the APM BIOS version - movw %cx, (76) # and flags - jmp done_apm_bios - -apm_disconnect: # Tidy up - movw $0x05304, %ax # Disconnect - xorw %bx, %bx - int $0x15 # ignore return code - - jmp done_apm_bios - -no_32_apm_bios: - andw $0xfffd, (76) # remove 32 bit support bit -done_apm_bios: -#endif - -#include "edd.S" - -# Now we want to move to protected mode ... - cmpw $0, %cs:realmode_swtch - jz rmodeswtch_normal - - lcall *%cs:realmode_swtch - - jmp rmodeswtch_end - -rmodeswtch_normal: - pushw %cs - call default_switch - -rmodeswtch_end: -# Now we move the system to its rightful place ... but we check if we have a -# big-kernel. In that case we *must* not move it ... - testb $LOADED_HIGH, %cs:loadflags - jz do_move0 # .. then we have a normal low - # loaded zImage - # .. or else we have a high - # loaded bzImage - jmp end_move # ... and we skip moving - -do_move0: - movw $0x100, %ax # start of destination segment - movw %cs, %bp # aka SETUPSEG - subw $DELTA_INITSEG, %bp # aka INITSEG - movw %cs:start_sys_seg, %bx # start of source segment - cld -do_move: - movw %ax, %es # destination segment - incb %ah # instead of add ax,#0x100 - movw %bx, %ds # source segment - addw $0x100, %bx - subw %di, %di - subw %si, %si - movw $0x800, %cx - rep - movsw - cmpw %bp, %bx # assume start_sys_seg > 0x200, - # so we will perhaps read one - # page more than needed, but - # never overwrite INITSEG - # because destination is a - # minimum one page below source - jb do_move - -end_move: -# then we load the segment descriptors - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds - -# Check whether we need to be downward compatible with version <=201 - cmpl $0, cmd_line_ptr - jne end_move_self # loader uses version >=202 features - cmpb $0x20, type_of_loader - je end_move_self # bootsect loader, we know of it - -# Boot loader doesnt support boot protocol version 2.02. -# If we have our code not at 0x90000, we need to move it there now. -# We also then need to move the params behind it (commandline) -# Because we would overwrite the code on the current IP, we move -# it in two steps, jumping high after the first one. - movw %cs, %ax - cmpw $SETUPSEG, %ax - je end_move_self - - cli # make sure we really have - # interrupts disabled ! - # because after this the stack - # should not be used - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ss, %dx - cmpw %ax, %dx - jb move_self_1 - - addw $INITSEG, %dx - subw %ax, %dx # this will go into %ss after - # the move -move_self_1: - movw %ax, %ds - movw $INITSEG, %ax # real INITSEG - movw %ax, %es - movw %cs:setup_move_size, %cx - std # we have to move up, so we use - # direction down because the - # areas may overlap - movw %cx, %di - decw %di - movw %di, %si - subw $move_self_here+0x200, %cx - rep - movsb - ljmp $SETUPSEG, $move_self_here - -move_self_here: - movw $move_self_here+0x200, %cx - rep - movsb - movw $SETUPSEG, %ax - movw %ax, %ds - movw %dx, %ss -end_move_self: # now we are at the right place - -# -# Enable A20. This is at the very best an annoying procedure. -# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin. -# AMD Elan bug fix by Robert Schwebel. -# - -#if defined(CONFIG_X86_ELAN) - movb $0x02, %al # alternate A20 gate - outb %al, $0x92 # this works on SC410/SC520 -a20_elan_wait: - call a20_test - jz a20_elan_wait - jmp a20_done -#endif - - -A20_TEST_LOOPS = 32 # Iterations per wait -A20_ENABLE_LOOPS = 255 # Total loops to try - - -#ifndef CONFIG_X86_VOYAGER -a20_try_loop: - - # First, see if we are on a system with no A20 gate. -a20_none: - call a20_test - jnz a20_done - - # Next, try the BIOS (INT 0x15, AX=0x2401) -a20_bios: - movw $0x2401, %ax - pushfl # Be paranoid about flags - int $0x15 - popfl - - call a20_test - jnz a20_done - - # Try enabling A20 through the keyboard controller -#endif /* CONFIG_X86_VOYAGER */ -a20_kbc: - call empty_8042 - -#ifndef CONFIG_X86_VOYAGER - call a20_test # Just in case the BIOS worked - jnz a20_done # but had a delayed reaction. -#endif - - movb $0xD1, %al # command write - outb %al, $0x64 - call empty_8042 - - movb $0xDF, %al # A20 on - outb %al, $0x60 - call empty_8042 - -#ifndef CONFIG_X86_VOYAGER - # Wait until a20 really *is* enabled; it can take a fair amount of - # time on certain systems; Toshiba Tecras are known to have this - # problem. -a20_kbc_wait: - xorw %cx, %cx -a20_kbc_wait_loop: - call a20_test - jnz a20_done - loop a20_kbc_wait_loop - - # Final attempt: use "configuration port A" -a20_fast: - inb $0x92, %al # Configuration Port A - orb $0x02, %al # "fast A20" version - andb $0xFE, %al # don't accidentally reset - outb %al, $0x92 - - # Wait for configuration port A to take effect -a20_fast_wait: - xorw %cx, %cx -a20_fast_wait_loop: - call a20_test - jnz a20_done - loop a20_fast_wait_loop - - # A20 is still not responding. Try frobbing it again. - # - decb (a20_tries) - jnz a20_try_loop - - movw $a20_err_msg, %si - call prtstr - -a20_die: - hlt - jmp a20_die - -a20_tries: - .byte A20_ENABLE_LOOPS - -a20_err_msg: - .ascii "linux: fatal error: A20 gate not responding!" - .byte 13, 10, 0 - - # If we get here, all is good -a20_done: - -#endif /* CONFIG_X86_VOYAGER */ -# set up gdt and idt and 32bit start address - lidt idt_48 # load idt with 0,0 - xorl %eax, %eax # Compute gdt_base - movw %ds, %ax # (Convert %ds:gdt to a linear ptr) - shll $4, %eax - addl %eax, code32 - addl $gdt, %eax - movl %eax, (gdt_48+2) - lgdt gdt_48 # load gdt with whatever is - # appropriate - -# make sure any possible coprocessor is properly reset.. - xorw %ax, %ax - outb %al, $0xf0 - call delay - - outb %al, $0xf1 - call delay - -# well, that went ok, I hope. Now we mask all interrupts - the rest -# is done in init_IRQ(). - movb $0xFF, %al # mask all interrupts for now - outb %al, $0xA1 - call delay - - movb $0xFB, %al # mask all irq's but irq2 which - outb %al, $0x21 # is cascaded - -# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't -# need no steenking BIOS anyway (except for the initial loading :-). -# The BIOS-routine wants lots of unnecessary data, and it's less -# "interesting" anyway. This is how REAL programmers do it. -# -# Well, now's the time to actually move into protected mode. To make -# things as simple as possible, we do no register set-up or anything, -# we let the gnu-compiled 32-bit programs do that. We just jump to -# absolute address 0x1000 (or the loader supplied one), -# in 32-bit protected mode. -# -# Note that the short jump isn't strictly needed, although there are -# reasons why it might be a good idea. It won't hurt in any case. - movw $1, %ax # protected mode (PE) bit - lmsw %ax # This is it! - jmp flush_instr - -flush_instr: - xorw %bx, %bx # Flag to indicate a boot - xorl %esi, %esi # Pointer to real-mode code - movw %cs, %si - subw $DELTA_INITSEG, %si - shll $4, %esi # Convert to 32-bit pointer - -# jump to startup_32 in arch/i386/boot/compressed/head.S -# -# NOTE: For high loaded big kernels we need a -# jmpi 0x100000,__BOOT_CS -# -# but we yet haven't reloaded the CS register, so the default size -# of the target offset still is 16 bit. -# However, using an operand prefix (0x66), the CPU will properly -# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference -# Manual, Mixing 16-bit and 32-bit code, page 16-6) - - .byte 0x66, 0xea # prefix + jmpi-opcode -code32: .long startup_32 # will be set to %cs+startup_32 - .word __BOOT_CS -.code32 -startup_32: - movl $(__BOOT_DS), %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %fs - movl %eax, %gs - movl %eax, %ss - - xorl %eax, %eax -1: incl %eax # check that A20 really IS enabled - movl %eax, 0x00000000 # loop forever if it isn't - cmpl %eax, 0x00100000 - je 1b - - # Jump to the 32bit entry point - jmpl *(code32_start - start + (DELTA_INITSEG << 4))(%esi) -.code16 - -# Here's a bunch of information about your current kernel.. -kernel_version: .ascii UTS_RELEASE - .ascii " (" - .ascii LINUX_COMPILE_BY - .ascii "@" - .ascii LINUX_COMPILE_HOST - .ascii ") " - .ascii UTS_VERSION - .byte 0 - -# This is the default real mode switch routine. -# to be called just before protected mode transition -default_switch: - cli # no interrupts allowed ! - movb $0x80, %al # disable NMI for bootup - # sequence - outb %al, $0x70 - lret - - -#ifndef CONFIG_X86_VOYAGER -# This routine tests whether or not A20 is enabled. If so, it -# exits with zf = 0. -# -# The memory address used, 0x200, is the int $0x80 vector, which -# should be safe. - -A20_TEST_ADDR = 4*0x80 - -a20_test: - pushw %cx - pushw %ax - xorw %cx, %cx - movw %cx, %fs # Low memory - decw %cx - movw %cx, %gs # High memory area - movw $A20_TEST_LOOPS, %cx - movw %fs:(A20_TEST_ADDR), %ax - pushw %ax -a20_test_wait: - incw %ax - movw %ax, %fs:(A20_TEST_ADDR) - call delay # Serialize and make delay constant - cmpw %gs:(A20_TEST_ADDR+0x10), %ax - loope a20_test_wait - - popw %fs:(A20_TEST_ADDR) - popw %ax - popw %cx - ret - -#endif /* CONFIG_X86_VOYAGER */ - -# This routine checks that the keyboard command queue is empty -# (after emptying the output buffers) -# -# Some machines have delusions that the keyboard buffer is always full -# with no keyboard attached... -# -# If there is no keyboard controller, we will usually get 0xff -# to all the reads. With each IO taking a microsecond and -# a timeout of 100,000 iterations, this can take about half a -# second ("delay" == outb to port 0x80). That should be ok, -# and should also be plenty of time for a real keyboard controller -# to empty. -# - -empty_8042: - pushl %ecx - movl $100000, %ecx - -empty_8042_loop: - decl %ecx - jz empty_8042_end_loop - - call delay - - inb $0x64, %al # 8042 status port - testb $1, %al # output buffer? - jz no_output - - call delay - inb $0x60, %al # read it - jmp empty_8042_loop - -no_output: - testb $2, %al # is input buffer full? - jnz empty_8042_loop # yes - loop -empty_8042_end_loop: - popl %ecx - ret - -# Read the cmos clock. Return the seconds in al -gettime: - pushw %cx - movb $0x02, %ah - int $0x1a - movb %dh, %al # %dh contains the seconds - andb $0x0f, %al - movb %dh, %ah - movb $0x04, %cl - shrb %cl, %ah - aad - popw %cx - ret - -# Delay is needed after doing I/O -delay: - outb %al,$0x80 - ret - -# Descriptor tables -# -# NOTE: The intel manual says gdt should be sixteen bytes aligned for -# efficiency reasons. However, there are machines which are known not -# to boot with misaligned GDTs, so alter this at your peril! If you alter -# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two -# empty GDT entries (one for NULL and one reserved). -# -# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is -# true for the Voyager Quad CPU card which will not boot without -# This directive. 16 byte aligment is recommended by intel. -# - .align 16 -gdt: - .fill GDT_ENTRY_BOOT_CS,8,0 - - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) - .word 0 # base address = 0 - .word 0x9A00 # code read/exec - .word 0x00CF # granularity = 4096, 386 - # (+5th nibble of limit) - - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) - .word 0 # base address = 0 - .word 0x9200 # data read/write - .word 0x00CF # granularity = 4096, 386 - # (+5th nibble of limit) -gdt_end: - .align 4 - - .word 0 # alignment byte -idt_48: - .word 0 # idt limit = 0 - .word 0, 0 # idt base = 0L - - .word 0 # alignment byte -gdt_48: - .word gdt_end - gdt - 1 # gdt limit - .word 0, 0 # gdt base (filled in later) - -# Include video setup & detection code - -#include "video.S" - -# Setup signature -- must be last -setup_sig1: .word SIG1 -setup_sig2: .word SIG2 - -# After this point, there is some free space which is used by the video mode -# handling code to store the temporary mode table (not used by the kernel). - -modelist: - -.text -endtext: -.data -enddata: -.bss -endbss: --- /dev/null +++ b/arch/i386/boot/setup.ld @@ -0,0 +1,54 @@ +/* + * setup.ld + * + * Linker script for the i386 setup code + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0; + .bstext : { *(.bstext) } + .bsdata : { *(.bsdata) } + + . = 497; + .header : { *(.header) } + .inittext : { *(.inittext) } + .initdata : { *(.initdata) } + .text : { *(.text*) } + + . = ALIGN(16); + .rodata : { *(.rodata*) } + + .videocards : { + video_cards = .; + *(.videocards) + video_cards_end = .; + } + + . = ALIGN(16); + .data : { *(.data*) } + + .signature : { + setup_sig = .; + LONG(0x5a5aaa55) + } + + + . = ALIGN(16); + .bss : + { + __bss_start = .; + *(.bss) + __bss_end = .; + } + . = ALIGN(16); + _end = .; + + /DISCARD/ : { *(.note*) } + + . = ASSERT(_end <= 0x8000, "Setup too big!"); + . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!"); +} --- /dev/null +++ b/arch/i386/boot/string.c @@ -0,0 +1,34 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/string.c + * + * Very basic string functions + */ + +#include "boot.h" +#include + +int strcmp(const char *str1, const char *str2) +{ + const unsigned char *s1 = (const unsigned char *)str1; + const unsigned char *s2 = (const unsigned char *)str2; + int delta = 0; + + while (*s1 || *s2) { + delta = *s2 - *s1; + if (delta) + return delta; + s1++; + s2++; + } + return 0; +} --- a/arch/i386/boot/tools/build.c +++ b/arch/i386/boot/tools/build.c @@ -1,13 +1,12 @@ /* * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1997 Martin Mares + * Copyright (C) 2007 H. Peter Anvin */ /* * This file builds a disk-image from three different files: * - * - bootsect: compatibility mbr which prints an error message if - * someone tries to boot the kernel directly. * - setup: 8086 machine code, sets up system parm * - system: 80386 code for actual system * @@ -21,6 +20,7 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 * Cross compiling fixes by Gertjan van Wingerde, July 1996 * Rewritten by Martin Mares, April 1997 + * Substantially overhauled by H. Peter Anvin, April 2007 */ #include @@ -32,23 +32,25 @@ #include #include #include +#include #include -typedef unsigned char byte; -typedef unsigned short word; -typedef unsigned long u32; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; #define DEFAULT_MAJOR_ROOT 0 #define DEFAULT_MINOR_ROOT 0 -/* Minimal number of setup sectors (see also bootsect.S) */ -#define SETUP_SECTS 4 +/* Minimal number of setup sectors */ +#define SETUP_SECT_MIN 5 +#define SETUP_SECT_MAX 64 -byte buf[1024]; -int fd; +/* This must be large enough to hold the entire setup */ +u8 buf[SETUP_SECT_MAX*512]; int is_big_kernel; -void die(const char * str, ...) +static void die(const char * str, ...) { va_list args; va_start(args, str); @@ -57,15 +59,9 @@ exit(1); } -void file_open(const char *name) +static void usage(void) { - if ((fd = open(name, O_RDONLY, 0)) < 0) - die("Unable to open `%s': %m", name); -} - -void usage(void) -{ - die("Usage: build [-b] bootsect setup system [rootdev] [> image]"); + die("Usage: build [-b] setup system [rootdev] [> image]"); } int main(int argc, char ** argv) @@ -73,27 +69,30 @@ unsigned int i, sz, setup_sectors; int c; u32 sys_size; - byte major_root, minor_root; + u8 major_root, minor_root; struct stat sb; + FILE *file; + int fd; + void *kernel; if (argc > 2 && !strcmp(argv[1], "-b")) { is_big_kernel = 1; argc--, argv++; } - if ((argc < 4) || (argc > 5)) + if ((argc < 3) || (argc > 4)) usage(); - if (argc > 4) { - if (!strcmp(argv[4], "CURRENT")) { + if (argc > 3) { + if (!strcmp(argv[3], "CURRENT")) { if (stat("/", &sb)) { perror("/"); die("Couldn't stat /"); } major_root = major(sb.st_dev); minor_root = minor(sb.st_dev); - } else if (strcmp(argv[4], "FLOPPY")) { - if (stat(argv[4], &sb)) { - perror(argv[4]); + } else if (strcmp(argv[3], "FLOPPY")) { + if (stat(argv[3], &sb)) { + perror(argv[3]); die("Couldn't stat root device."); } major_root = major(sb.st_rdev); @@ -108,79 +107,62 @@ } fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); - file_open(argv[1]); - i = read(fd, buf, sizeof(buf)); - fprintf(stderr,"Boot sector %d bytes.\n",i); - if (i != 512) - die("Boot block must be exactly 512 bytes"); + /* Copy the setup code */ + file = fopen(argv[1], "r"); + if (!file) + die("Unable to open `%s': %m", argv[1]); + c = fread(buf, 1, sizeof(buf), file); + if (ferror(file)) + die("read-error on `setup'"); + if (c < 1024) + die("The setup must be at least 1024 bytes"); if (buf[510] != 0x55 || buf[511] != 0xaa) die("Boot block hasn't got boot flag (0xAA55)"); + fclose(file); + + /* Pad unused space with zeros */ + setup_sectors = (c + 511) / 512; + if (setup_sectors < SETUP_SECT_MIN) + setup_sectors = SETUP_SECT_MIN; + i = setup_sectors*512; + memset(buf+c, 0, i-c); + + /* Set the default root device */ buf[508] = minor_root; buf[509] = major_root; - if (write(1, buf, 512) != 512) - die("Write call failed"); - close (fd); - - file_open(argv[2]); /* Copy the setup code */ - for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c ) - if (write(1, buf, c) != c) - die("Write call failed"); - if (c != 0) - die("read-error on `setup'"); - close (fd); - setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */ - /* for compatibility with ancient versions of LILO. */ - if (setup_sectors < SETUP_SECTS) - setup_sectors = SETUP_SECTS; - fprintf(stderr, "Setup is %d bytes.\n", i); - memset(buf, 0, sizeof(buf)); - while (i < setup_sectors * 512) { - c = setup_sectors * 512 - i; - if (c > sizeof(buf)) - c = sizeof(buf); - if (write(1, buf, c) != c) - die("Write call failed"); - i += c; - } + fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i); - file_open(argv[3]); - if (fstat (fd, &sb)) - die("Unable to stat `%s': %m", argv[3]); + /* Open and stat the kernel file */ + fd = open(argv[2], O_RDONLY); + if (fd < 0) + die("Unable to open `%s': %m", argv[2]); + if (fstat(fd, &sb)) + die("Unable to stat `%s': %m", argv[2]); sz = sb.st_size; - fprintf (stderr, "System is %d kB\n", sz/1024); + fprintf (stderr, "System is %d kB\n", (sz+1023)/1024); + kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0); + if (kernel == MAP_FAILED) + die("Unable to mmap '%s': %m", argv[2]); sys_size = (sz + 15) / 16; if (!is_big_kernel && sys_size > DEF_SYSSIZE) die("System is too big. Try using bzImage or modules."); - while (sz > 0) { - int l, n; - l = (sz > sizeof(buf)) ? sizeof(buf) : sz; - if ((n=read(fd, buf, l)) != l) { - if (n < 0) - die("Error reading %s: %m", argv[3]); - else - die("%s: Unexpected EOF", argv[3]); - } - if (write(1, buf, l) != l) - die("Write failed"); - sz -= l; - } + /* Patch the setup code with the appropriate size parameters */ + buf[0x1f1] = setup_sectors-1; + buf[0x1f4] = sys_size; + buf[0x1f5] = sys_size >> 8; + buf[0x1f6] = sys_size >> 16; + buf[0x1f7] = sys_size >> 24; + + if (fwrite(buf, 1, i, stdout) != i) + die("Writing setup failed"); + + /* Copy the kernel code */ + if (fwrite(kernel, 1, sz, stdout) != sz) + die("Writing kernel failed"); close(fd); - if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */ - die("Output: seek failed"); - buf[0] = setup_sectors; - if (write(1, buf, 1) != 1) - die("Write of setup sector count failed"); - if (lseek(1, 500, SEEK_SET) != 500) - die("Output: seek failed"); - buf[0] = (sys_size & 0xff); - buf[1] = ((sys_size >> 8) & 0xff); - buf[2] = ((sys_size >> 16) & 0xff); - buf[3] = ((sys_size >> 24) & 0xff); - if (write(1, buf, 4) != 4) - die("Write of image length failed"); - - return 0; /* Everything is OK */ + /* Everything is OK */ + return 0; } --- /dev/null +++ b/arch/i386/boot/tty.c @@ -0,0 +1,112 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/tty.c + * + * Very simple screen I/O + * XXX: Probably should add very simple serial I/O? + */ + +#include "boot.h" + +/* + * These functions are in .inittext so they can be used to signal + * error during initialization. + */ + +void __attribute__((section(".inittext"))) putchar(int ch) +{ + unsigned char c = ch; + + if (c == '\n') + putchar('\r'); /* \n -> \r\n */ + + /* int $0x10 is known to have bugs involving touching registers + it shouldn't. Be extra conservative... */ + asm volatile("pushal; int $0x10; popal" + : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch)); +} + +void __attribute__((section(".inittext"))) puts(const char *str) +{ + int n = 0; + while (*str) { + putchar(*str++); + n++; + } +} + +/* + * Read the CMOS clock through the BIOS, and return the + * seconds in BCD. + */ + +static u8 gettime(void) +{ + u16 ax = 0x0200; + u16 cx, dx; + + asm("int $0x1a" + : "+a" (ax), "=c" (cx), "=d" (dx) + : : "ebx", "esi", "edi"); + + return dx >> 8; +} + +/* + * Read from the keyboard + */ +int getchar(void) +{ + u16 ax = 0; + asm("int $0x16" : "+a" (ax)); + + return ax & 0xff; +} + +static int kbd_pending(void) +{ + u8 pending; + asm("int $0x16; setnz %0" + : "=rm" (pending) + : "a" (0x0100)); + return pending; +} + +void kbd_flush(void) +{ + for (;;) { + if (!kbd_pending()) + break; + getchar(); + } +} + +int getchar_timeout(void) +{ + int cnt = 30; + int t0, t1; + + t0 = gettime(); + + while (cnt) { + if (kbd_pending()) + return getchar(); + + t1 = gettime(); + if (t0 != t1) { + cnt--; + t0 = t1; + } + } + + return 0; /* Timeout! */ +} --- /dev/null +++ b/arch/i386/boot/version.c @@ -0,0 +1,23 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/version.c + * + * Kernel version string + */ + +#include "boot.h" +#include +#include + +const char kernel_version[] = + UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") " + UTS_VERSION; --- /dev/null +++ b/arch/i386/boot/vesa.h @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1999-2007 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#ifndef BOOT_VESA_H +#define BOOT_VESA_H + +typedef struct { + u16 off, seg; +} far_ptr; + +/* VESA General Information table */ +struct vesa_general_info { + u32 signature; /* 0 Magic number = "VESA" */ + u16 version; /* 4 */ + far_ptr vendor_string; /* 6 */ + u32 capabilities; /* 10 */ + far_ptr video_mode_ptr; /* 14 */ + u16 total_memory; /* 18 */ + + u16 oem_software_rev; /* 20 */ + far_ptr oem_vendor_name_ptr; /* 22 */ + far_ptr oem_product_name_ptr; /* 26 */ + far_ptr oem_product_rev_ptr; /* 30 */ + + u8 reserved[222]; /* 34 */ + u8 oem_data[256]; /* 256 */ +} __attribute__((packed)); + +#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24)) +#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24)) + +struct vesa_mode_info { + u16 mode_attr; /* 0 */ + u8 win_attr[2]; /* 2 */ + u16 win_grain; /* 4 */ + u16 win_size; /* 6 */ + u16 win_seg[2]; /* 8 */ + far_ptr win_scheme; /* 12 */ + u16 logical_scan; /* 16 */ + + u16 h_res; /* 18 */ + u16 v_res; /* 20 */ + u8 char_width; /* 22 */ + u8 char_height; /* 23 */ + u8 memory_planes; /* 24 */ + u8 bpp; /* 25 */ + u8 banks; /* 26 */ + u8 memory_layout; /* 27 */ + u8 bank_size; /* 28 */ + u8 image_planes; /* 29 */ + u8 page_function; /* 30 */ + + u8 rmask; /* 31 */ + u8 rpos; /* 32 */ + u8 gmask; /* 33 */ + u8 gpos; /* 34 */ + u8 bmask; /* 35 */ + u8 bpos; /* 36 */ + u8 resv_mask; /* 37 */ + u8 resv_pos; /* 38 */ + u8 dcm_info; /* 39 */ + + u32 lfb_ptr; /* 40 Linear frame buffer address */ + u32 offscreen_ptr; /* 44 Offscreen memory address */ + u16 offscreen_size; /* 48 */ + + u8 reserved[206]; /* 50 */ +} __attribute__((packed)); + +#endif /* LIB_SYS_VESA_H */ --- /dev/null +++ b/arch/i386/boot/video-bios.c @@ -0,0 +1,125 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/video-bios.c + * + * Standard video BIOS modes + * + * We have two options for this; silent and scanned. + */ + +#include "boot.h" +#include "video.h" + +__videocard video_bios; + +/* Set a conventional BIOS mode */ +static int set_bios_mode(u8 mode); + +static int bios_set_mode(struct mode_info *mi) +{ + return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS); +} + +static int set_bios_mode(u8 mode) +{ + u16 ax; + u8 new_mode; + + ax = mode; /* AH=0x00 Set Video Mode */ + asm volatile(INT10 + : "+a" (ax) + : : "ebx", "ecx", "edx", "esi", "edi"); + + ax = 0x0f00; /* Get Current Video Mode */ + asm volatile(INT10 + : "+a" (ax) + : : "ebx", "ecx", "edx", "esi", "edi"); + + do_restore = 1; /* Assume video contents was lost */ + new_mode = ax & 0x7f; /* Not all BIOSes are clean with the top bit */ + + if (new_mode == mode) + return 0; /* Mode change OK */ + + if (new_mode != boot_params.screen_info.orig_video_mode) { + /* Mode setting failed, but we didn't end up where we + started. That's bad. Try to revert to the original + video mode. */ + ax = boot_params.screen_info.orig_video_mode; + asm volatile(INT10 + : "+a" (ax) + : : "ebx", "ecx", "edx", "esi", "edi"); + } + return -1; +} + +static int bios_probe(void) +{ + u8 mode; + u8 saved_mode = boot_params.screen_info.orig_video_mode; + u16 crtc; + struct mode_info *mi; + int nmodes = 0; + + if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA) + return 0; + + set_fs(0); + crtc = vga_crtc(); + + video_bios.modes = GET_HEAP(struct mode_info, 0); + + for (mode = 0x14; mode <= 0x7f; mode++) { + if (heap_free() < sizeof(struct mode_info)) + break; + + if (mode_defined(VIDEO_FIRST_BIOS+mode)) + continue; + + if (set_bios_mode(mode)) + continue; + + /* Try to verify that it's a text mode. */ + + /* Attribute Controller: make graphics controller disabled */ + if (in_idx(0x3c0, 0x10) & 0x01) + continue; + + /* Graphics Controller: verify Alpha addressing enabled */ + if (in_idx(0x3ce, 0x06) & 0x01) + continue; + + /* CRTC cursor location low should be zero(?) */ + if (in_idx(crtc, 0x0f)) + continue; + + mi = GET_HEAP(struct mode_info, 1); + mi->mode = VIDEO_FIRST_BIOS+mode; + mi->x = rdfs16(0x44a); + mi->y = rdfs8(0x484)+1; + nmodes++; + } + + set_bios_mode(saved_mode); + + return nmodes; +} + +__videocard video_bios = +{ + .card_name = "BIOS (scanned)", + .probe = bios_probe, + .set_mode = bios_set_mode, + .unsafe = 1, + .xmode_first = VIDEO_FIRST_BIOS, + .xmode_n = 0x80, +}; --- /dev/null +++ b/arch/i386/boot/video-vesa.c @@ -0,0 +1,283 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/video-vesa.c + * + * VESA text modes + */ + +#include "boot.h" +#include "video.h" +#include "vesa.h" + +/* VESA information */ +static struct vesa_general_info vginfo; +static struct vesa_mode_info vminfo; + +__videocard video_vesa; + +static void vesa_store_mode_params_graphics(void); + +static int vesa_probe(void) +{ +#ifdef CONFIG_VIDEO_VESA + u16 ax; + u16 mode; + addr_t mode_ptr; + struct mode_info *mi; + int nmodes = 0; + + video_vesa.modes = GET_HEAP(struct mode_info, 0); + + vginfo.signature = VBE2_MAGIC; + + /* Optimistically assume a VESA BIOS is register-clean... */ + ax = 0x4f00; + asm("int $0x10" : "+a" (ax), "=m" (vginfo) : "D" (&vginfo)); + + if (ax != 0x004f || + vginfo.signature != VESA_MAGIC || + vginfo.version < 0x0102) + return 0; /* Not present */ + + set_fs(vginfo.video_mode_ptr.seg); + mode_ptr = vginfo.video_mode_ptr.off; + + while ((mode = rdfs16(mode_ptr)) != 0xffff) { + mode_ptr += 2; + + if (heap_free() < sizeof(struct mode_info)) + break; /* Heap full, can't save mode info */ + + if (mode & ~0x1ff) + continue; + + memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ + + ax = 0x4f01; + asm("int $0x10" + : "+a" (ax), "=m" (vminfo) + : "c" (mode), "D" (&vminfo)); + + if (ax != 0x004f) + continue; + + if ((vminfo.mode_attr & 0x15) == 0x05) { + /* Text Mode, TTY BIOS supported, + supported by hardware */ + mi = GET_HEAP(struct mode_info, 1); + mi->mode = mode + VIDEO_FIRST_VESA; + mi->x = vminfo.h_res; + mi->y = vminfo.v_res; + nmodes++; + } else if ((vminfo.mode_attr & 0x99) == 0x99) { +#ifdef CONFIG_FB + /* Graphics mode, color, linear frame buffer + supported -- register the mode but hide from + the menu. Only do this if framebuffer is + configured, however, otherwise the user will + be left without a screen. */ + mi = GET_HEAP(struct mode_info, 1); + mi->mode = mode + VIDEO_FIRST_VESA; + mi->x = mi->y = 0; + nmodes++; +#endif + } + } + + return nmodes; +#else + return 0; +#endif +} + +static int vesa_set_mode(struct mode_info *mode) +{ + u16 ax; + int is_graphic; + u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA; + + memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ + + ax = 0x4f01; + asm("int $0x10" + : "+a" (ax), "=m" (vminfo) + : "c" (vesa_mode), "D" (&vminfo)); + + if (ax != 0x004f) + return -1; + + if ((vminfo.mode_attr & 0x15) == 0x05) { + /* It's a supported text mode */ + is_graphic = 0; + } else if ((vminfo.mode_attr & 0x99) == 0x99) { + /* It's a graphics mode with linear frame buffer */ + is_graphic = 1; + vesa_mode |= 0x4000; /* Request linear frame buffer */ + } else { + return -1; /* Invalid mode */ + } + + + ax = 0x4f02; + asm volatile("int $0x10" + : "+a" (ax) + : "b" (vesa_mode), "D" (0)); + + if (ax != 0x004f) + return -1; + + graphic_mode = is_graphic; + if (!is_graphic) { + /* Text mode */ + force_x = mode->x; + force_y = mode->y; + do_restore = 1; + } else { + /* Graphics mode */ + vesa_store_mode_params_graphics(); + } + + return 0; +} + + +/* Switch DAC to 8-bit mode */ +static void vesa_dac_set_8bits(void) +{ + u8 dac_size = 6; + + /* If possible, switch the DAC to 8-bit mode */ + if (vginfo.capabilities & 1) { + u16 ax, bx; + + ax = 0x4f08; + bx = 0x0800; + asm volatile(INT10 + : "+a" (ax), "+b" (bx) + : : "ecx", "edx", "esi", "edi"); + + if (ax == 0x004f) + dac_size = bx >> 8; + } + + /* Set the color sizes to the DAC size, and offsets to 0 */ + boot_params.screen_info.red_size = dac_size; + boot_params.screen_info.green_size = dac_size; + boot_params.screen_info.blue_size = dac_size; + boot_params.screen_info.rsvd_size = dac_size; + + boot_params.screen_info.red_pos = 0; + boot_params.screen_info.green_pos = 0; + boot_params.screen_info.blue_pos = 0; + boot_params.screen_info.rsvd_pos = 0; +} + +/* Save the VESA protected mode info */ +static void vesa_store_pm_info(void) +{ + u16 ax, bx, di, es; + + ax = 0x4f0a; + bx = di = 0; + asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es" + : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di) + : : "ecx", "esi"); + + if (ax != 0x004f) + return; + + boot_params.screen_info.vesapm_seg = es; + boot_params.screen_info.vesapm_off = di; +} + +/* + * Save video mode parameters for graphics mode + */ +static void vesa_store_mode_params_graphics(void) +{ + /* Tell the kernel we're in VESA graphics mode */ + boot_params.screen_info.orig_video_isVGA = 0x23; + + /* Mode parameters */ + boot_params.screen_info.vesa_attributes = vminfo.mode_attr; + boot_params.screen_info.lfb_linelength = vminfo.logical_scan; + boot_params.screen_info.lfb_width = vminfo.h_res; + boot_params.screen_info.lfb_height = vminfo.v_res; + boot_params.screen_info.lfb_depth = vminfo.bpp; + boot_params.screen_info.pages = vminfo.image_planes; + boot_params.screen_info.lfb_base = vminfo.lfb_ptr; + memcpy(&boot_params.screen_info.red_size, + &vminfo.rmask, 8); + + /* General parameters */ + boot_params.screen_info.lfb_size = vginfo.total_memory; + + if (vminfo.bpp <= 8) + vesa_dac_set_8bits(); + + vesa_store_pm_info(); +} + +/* + * Save EDID information for the kernel; this is invoked, separately, + * after mode-setting. + */ +void vesa_store_edid(void) +{ +#ifdef CONFIG_FIRMWARE_EDID + u16 ax, bx, cx, dx, di; + + /* Apparently used as a nonsense token... */ + memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info); + + if (vginfo.version < 0x0200) + return; /* EDID requires VBE 2.0+ */ + + ax = 0x4f15; /* VBE DDC */ + bx = 0x0000; /* Report DDC capabilities */ + cx = 0; /* Controller 0 */ + di = 0; /* ES:DI must be 0 by spec */ + + /* Note: The VBE DDC spec is different from the main VESA spec; + we genuinely have to assume all registers are destroyed here. */ + + asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" + : "+a" (ax), "+b" (bx) + : "c" (cx), "D" (di) + : "esi"); + + if (ax != 0x004f) + return; /* No EDID */ + + /* BH = time in seconds to transfer EDD information */ + /* BL = DDC level supported */ + + ax = 0x4f15; /* VBE DDC */ + bx = 0x0001; /* Read EDID */ + cx = 0; /* Controller 0 */ + dx = 0; /* EDID block number */ + di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */ + asm(INT10 + : "+a" (ax), "+b" (bx), "+d" (dx) + : "c" (cx), "D" (di) + : "esi"); +#endif /* CONFIG_FIRMWARE_EDID */ +} + +__videocard video_vesa = +{ + .card_name = "VESA", + .probe = vesa_probe, + .set_mode = vesa_set_mode, + .xmode_first = VIDEO_FIRST_VESA, + .xmode_n = 0x200, +}; --- /dev/null +++ b/arch/i386/boot/video-vga.c @@ -0,0 +1,260 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/video-vga.c + * + * Common all-VGA modes + */ + +#include "boot.h" +#include "video.h" + +static struct mode_info vga_modes[] = { + { VIDEO_80x25, 80, 25 }, + { VIDEO_8POINT, 80, 50 }, + { VIDEO_80x43, 80, 43 }, + { VIDEO_80x28, 80, 28 }, + { VIDEO_80x30, 80, 30 }, + { VIDEO_80x34, 80, 34 }, + { VIDEO_80x60, 80, 60 }, +}; + +static struct mode_info ega_modes[] = { + { VIDEO_80x25, 80, 25 }, + { VIDEO_8POINT, 80, 43 }, +}; + +static struct mode_info cga_modes[] = { + { VIDEO_80x25, 80, 25 }, +}; + +__videocard video_vga; + +/* Set basic 80x25 mode */ +static u8 vga_set_basic_mode(void) +{ + u16 ax; + u8 rows; + u8 mode; + +#ifdef CONFIG_VIDEO_400_HACK + if (adapter >= ADAPTER_VGA) { + asm(INT10 + : : "a" (0x1202), "b" (0x0030) + : "ecx", "edx", "esi", "edi"); + } +#endif + + ax = 0x0f00; + asm(INT10 + : "+a" (ax) + : : "ebx", "ecx", "edx", "esi", "edi"); + + mode = (u8)ax; + + set_fs(0); + rows = rdfs8(0x484); /* rows minus one */ + +#ifndef CONFIG_VIDEO_400_HACK + if ((ax == 0x5003 || ax == 0x5007) && + (rows == 0 || rows == 24)) + return mode; +#endif + + if (mode != 3 && mode != 7) + mode = 3; + + /* Set the mode */ + asm volatile(INT10 + : : "a" (mode) + : "ebx", "ecx", "edx", "esi", "edi"); + do_restore = 1; + return mode; +} + +static void vga_set_8font(void) +{ + /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */ + + /* Set 8x8 font */ + asm volatile(INT10 : : "a" (0x1112), "b" (0)); + + /* Use alternate print screen */ + asm volatile(INT10 : : "a" (0x1200), "b" (0x20)); + + /* Turn off cursor emulation */ + asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); + + /* Cursor is scan lines 6-7 */ + asm volatile(INT10 : : "a" (0x0100), "c" (0x0607)); +} + +static void vga_set_14font(void) +{ + /* Set 9x14 font - 80x28 on VGA */ + + /* Set 9x14 font */ + asm volatile(INT10 : : "a" (0x1111), "b" (0)); + + /* Turn off cursor emulation */ + asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); + + /* Cursor is scan lines 11-12 */ + asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c)); +} + +static void vga_set_80x43(void) +{ + /* Set 80x43 mode on VGA (not EGA) */ + + /* Set 350 scans */ + asm volatile(INT10 : : "a" (0x1201), "b" (0x30)); + + /* Reset video mode */ + asm volatile(INT10 : : "a" (0x0003)); + + vga_set_8font(); +} + +/* I/O address of the VGA CRTC */ +u16 vga_crtc(void) +{ + return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4; +} + +static void vga_set_480_scanlines(int end) +{ + u16 crtc; + u8 csel; + + crtc = vga_crtc(); + + out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */ + out_idx(0x0b, crtc, 0x06); /* Vertical total */ + out_idx(0x3e, crtc, 0x07); /* Vertical overflow */ + out_idx(0xea, crtc, 0x10); /* Vertical sync start */ + out_idx(end, crtc, 0x12); /* Vertical display end */ + out_idx(0xe7, crtc, 0x15); /* Vertical blank start */ + out_idx(0x04, crtc, 0x16); /* Vertical blank end */ + csel = inb(0x3cc); + csel &= 0x0d; + csel |= 0xe2; + outb(csel, 0x3cc); +} + +static void vga_set_80x30(void) +{ + vga_set_480_scanlines(0xdf); +} + +static void vga_set_80x34(void) +{ + vga_set_14font(); + vga_set_480_scanlines(0xdb); +} + +static void vga_set_80x60(void) +{ + vga_set_8font(); + vga_set_480_scanlines(0xdf); +} + +static int vga_set_mode(struct mode_info *mode) +{ + /* Set the basic mode */ + vga_set_basic_mode(); + + /* Override a possibly broken BIOS */ + force_x = mode->x; + force_y = mode->y; + + switch (mode->mode) { + case VIDEO_80x25: + break; + case VIDEO_8POINT: + vga_set_8font(); + break; + case VIDEO_80x43: + vga_set_80x43(); + break; + case VIDEO_80x28: + vga_set_14font(); + break; + case VIDEO_80x30: + vga_set_80x30(); + break; + case VIDEO_80x34: + vga_set_80x34(); + break; + case VIDEO_80x60: + vga_set_80x60(); + break; + } + + return 0; +} + +/* + * Note: this probe includes basic information required by all + * systems. It should be executed first, by making sure + * video-vga.c is listed first in the Makefile. + */ +static int vga_probe(void) +{ + static const char *card_name[] = { + "CGA/MDA/HGC", "EGA", "VGA" + }; + static struct mode_info *mode_lists[] = { + cga_modes, + ega_modes, + vga_modes, + }; + static int mode_count[] = { + sizeof(cga_modes)/sizeof(struct mode_info), + sizeof(ega_modes)/sizeof(struct mode_info), + sizeof(vga_modes)/sizeof(struct mode_info), + }; + u8 vga_flag; + + asm(INT10 + : "=b" (boot_params.screen_info.orig_video_ega_bx) + : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ + : "ecx", "edx", "esi", "edi"); + + /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ + if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) { + /* EGA/VGA */ + asm(INT10 + : "=a" (vga_flag) + : "a" (0x1a00) + : "ebx", "ecx", "edx", "esi", "edi"); + + if (vga_flag == 0x1a) { + adapter = ADAPTER_VGA; + boot_params.screen_info.orig_video_isVGA = 1; + } else { + adapter = ADAPTER_EGA; + } + } else { + adapter = ADAPTER_CGA; + } + + video_vga.modes = mode_lists[adapter]; + video_vga.card_name = card_name[adapter]; + return mode_count[adapter]; +} + +__videocard video_vga = +{ + .card_name = "VGA", + .probe = vga_probe, + .set_mode = vga_set_mode, +}; --- a/arch/i386/boot/video.S +++ /dev/null @@ -1,2043 +0,0 @@ -/* video.S - * - * Display adapter & video mode setup, version 2.13 (14-May-99) - * - * Copyright (C) 1995 -- 1998 Martin Mares - * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson - * - * Rewritten to use GNU 'as' by Chris Noe May 1999 - * - * For further information, look at Documentation/svga.txt. - * - */ - -/* Enable autodetection of SVGA adapters and modes. */ -#undef CONFIG_VIDEO_SVGA - -/* Enable autodetection of VESA modes */ -#define CONFIG_VIDEO_VESA - -/* Enable compacting of mode table */ -#define CONFIG_VIDEO_COMPACT - -/* Retain screen contents when switching modes */ -#define CONFIG_VIDEO_RETAIN - -/* Enable local mode list */ -#undef CONFIG_VIDEO_LOCAL - -/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */ -#undef CONFIG_VIDEO_400_HACK - -/* Hack that lets you force specific BIOS mode ID and specific dimensions */ -#undef CONFIG_VIDEO_GFX_HACK -#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */ -#define VIDEO_GFX_BIOS_BX 0x0102 -#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */ - -/* This code uses an extended set of video mode numbers. These include: - * Aliases for standard modes - * NORMAL_VGA (-1) - * EXTENDED_VGA (-2) - * ASK_VGA (-3) - * Video modes numbered by menu position -- NOT RECOMMENDED because of lack - * of compatibility when extending the table. These are between 0x00 and 0xff. - */ -#define VIDEO_FIRST_MENU 0x0000 - -/* Standard BIOS video modes (BIOS number + 0x0100) */ -#define VIDEO_FIRST_BIOS 0x0100 - -/* VESA BIOS video modes (VESA number + 0x0200) */ -#define VIDEO_FIRST_VESA 0x0200 - -/* Video7 special modes (BIOS number + 0x0900) */ -#define VIDEO_FIRST_V7 0x0900 - -/* Special video modes */ -#define VIDEO_FIRST_SPECIAL 0x0f00 -#define VIDEO_80x25 0x0f00 -#define VIDEO_8POINT 0x0f01 -#define VIDEO_80x43 0x0f02 -#define VIDEO_80x28 0x0f03 -#define VIDEO_CURRENT_MODE 0x0f04 -#define VIDEO_80x30 0x0f05 -#define VIDEO_80x34 0x0f06 -#define VIDEO_80x60 0x0f07 -#define VIDEO_GFX_HACK 0x0f08 -#define VIDEO_LAST_SPECIAL 0x0f09 - -/* Video modes given by resolution */ -#define VIDEO_FIRST_RESOLUTION 0x1000 - -/* The "recalculate timings" flag */ -#define VIDEO_RECALC 0x8000 - -/* Positions of various video parameters passed to the kernel */ -/* (see also include/linux/tty.h) */ -#define PARAM_CURSOR_POS 0x00 -#define PARAM_VIDEO_PAGE 0x04 -#define PARAM_VIDEO_MODE 0x06 -#define PARAM_VIDEO_COLS 0x07 -#define PARAM_VIDEO_EGA_BX 0x0a -#define PARAM_VIDEO_LINES 0x0e -#define PARAM_HAVE_VGA 0x0f -#define PARAM_FONT_POINTS 0x10 - -#define PARAM_LFB_WIDTH 0x12 -#define PARAM_LFB_HEIGHT 0x14 -#define PARAM_LFB_DEPTH 0x16 -#define PARAM_LFB_BASE 0x18 -#define PARAM_LFB_SIZE 0x1c -#define PARAM_LFB_LINELENGTH 0x24 -#define PARAM_LFB_COLORS 0x26 -#define PARAM_VESAPM_SEG 0x2e -#define PARAM_VESAPM_OFF 0x30 -#define PARAM_LFB_PAGES 0x32 -#define PARAM_VESA_ATTRIB 0x34 -#define PARAM_CAPABILITIES 0x36 - -/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ -#ifdef CONFIG_VIDEO_RETAIN -#define DO_STORE call store_screen -#else -#define DO_STORE -#endif /* CONFIG_VIDEO_RETAIN */ - -# This is the main entry point called by setup.S -# %ds *must* be pointing to the bootsector -video: pushw %ds # We use different segments - pushw %ds # FS contains original DS - popw %fs - pushw %cs # DS is equal to CS - popw %ds - pushw %cs # ES is equal to CS - popw %es - xorw %ax, %ax - movw %ax, %gs # GS is zero - cld - call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA) -#ifdef CONFIG_VIDEO_SELECT - movw %fs:(0x01fa), %ax # User selected video mode - cmpw $ASK_VGA, %ax # Bring up the menu - jz vid2 - - call mode_set # Set the mode - jc vid1 - - leaw badmdt, %si # Invalid mode ID - call prtstr -vid2: call mode_menu -vid1: -#ifdef CONFIG_VIDEO_RETAIN - call restore_screen # Restore screen contents -#endif /* CONFIG_VIDEO_RETAIN */ - call store_edid -#endif /* CONFIG_VIDEO_SELECT */ - call mode_params # Store mode parameters - popw %ds # Restore original DS - ret - -# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel. -basic_detect: - movb $0, %fs:(PARAM_HAVE_VGA) - movb $0x12, %ah # Check EGA/VGA - movb $0x10, %bl - int $0x10 - movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel - cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card. - je basret - - incb adapter - movw $0x1a00, %ax # Check EGA or VGA? - int $0x10 - cmpb $0x1a, %al # 1a means VGA... - jne basret # anything else is EGA. - - incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA - incb adapter -basret: ret - -# Store the video mode parameters for later usage by the kernel. -# This is done by asking the BIOS except for the rows/columns -# parameters in the default 80x25 mode -- these are set directly, -# because some very obscure BIOSes supply insane values. -mode_params: -#ifdef CONFIG_VIDEO_SELECT - cmpb $0, graphic_mode - jnz mopar_gr -#endif - movb $0x03, %ah # Read cursor position - xorb %bh, %bh - int $0x10 - movw %dx, %fs:(PARAM_CURSOR_POS) - movb $0x0f, %ah # Read page/mode/width - int $0x10 - movw %bx, %fs:(PARAM_VIDEO_PAGE) - movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width - cmpb $0x7, %al # MDA/HGA => segment differs - jnz mopar0 - - movw $0xb000, video_segment -mopar0: movw %gs:(0x485), %ax # Font size - movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA) - movw force_size, %ax # Forced size? - orw %ax, %ax - jz mopar1 - - movb %ah, %fs:(PARAM_VIDEO_COLS) - movb %al, %fs:(PARAM_VIDEO_LINES) - ret - -mopar1: movb $25, %al - cmpb $0, adapter # If we are on CGA/MDA/HGA, the - jz mopar2 # screen must have 25 lines. - - movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS - incb %al # location of max lines. -mopar2: movb %al, %fs:(PARAM_VIDEO_LINES) - ret - -#ifdef CONFIG_VIDEO_SELECT -# Fetching of VESA frame buffer parameters -mopar_gr: - leaw modelist+1024, %di - movb $0x23, %fs:(PARAM_HAVE_VGA) - movw 16(%di), %ax - movw %ax, %fs:(PARAM_LFB_LINELENGTH) - movw 18(%di), %ax - movw %ax, %fs:(PARAM_LFB_WIDTH) - movw 20(%di), %ax - movw %ax, %fs:(PARAM_LFB_HEIGHT) - movb 25(%di), %al - movb $0, %ah - movw %ax, %fs:(PARAM_LFB_DEPTH) - movb 29(%di), %al - movb $0, %ah - movw %ax, %fs:(PARAM_LFB_PAGES) - movl 40(%di), %eax - movl %eax, %fs:(PARAM_LFB_BASE) - movl 31(%di), %eax - movl %eax, %fs:(PARAM_LFB_COLORS) - movl 35(%di), %eax - movl %eax, %fs:(PARAM_LFB_COLORS+4) - movw 0(%di), %ax - movw %ax, %fs:(PARAM_VESA_ATTRIB) - -# get video mem size - leaw modelist+1024, %di - movw $0x4f00, %ax - int $0x10 - xorl %eax, %eax - movw 18(%di), %ax - movl %eax, %fs:(PARAM_LFB_SIZE) - -# store mode capabilities - movl 10(%di), %eax - movl %eax, %fs:(PARAM_CAPABILITIES) - -# switching the DAC to 8-bit is for <= 8 bpp only - movw %fs:(PARAM_LFB_DEPTH), %ax - cmpw $8, %ax - jg dac_done - -# get DAC switching capability - xorl %eax, %eax - movb 10(%di), %al - testb $1, %al - jz dac_set - -# attempt to switch DAC to 8-bit - movw $0x4f08, %ax - movw $0x0800, %bx - int $0x10 - cmpw $0x004f, %ax - jne dac_set - movb %bh, dac_size # store actual DAC size - -dac_set: -# set color size to DAC size - movb dac_size, %al - movb %al, %fs:(PARAM_LFB_COLORS+0) - movb %al, %fs:(PARAM_LFB_COLORS+2) - movb %al, %fs:(PARAM_LFB_COLORS+4) - movb %al, %fs:(PARAM_LFB_COLORS+6) - -# set color offsets to 0 - movb $0, %fs:(PARAM_LFB_COLORS+1) - movb $0, %fs:(PARAM_LFB_COLORS+3) - movb $0, %fs:(PARAM_LFB_COLORS+5) - movb $0, %fs:(PARAM_LFB_COLORS+7) - -dac_done: -# get protected mode interface informations - movw $0x4f0a, %ax - xorw %bx, %bx - xorw %di, %di - int $0x10 - cmp $0x004f, %ax - jnz no_pm - - movw %es, %fs:(PARAM_VESAPM_SEG) - movw %di, %fs:(PARAM_VESAPM_OFF) -no_pm: ret - -# The video mode menu -mode_menu: - leaw keymsg, %si # "Return/Space/Timeout" message - call prtstr - call flush -nokey: call getkt - - cmpb $0x0d, %al # ENTER ? - je listm # yes - manual mode selection - - cmpb $0x20, %al # SPACE ? - je defmd1 # no - repeat - - call beep - jmp nokey - -defmd1: ret # No mode chosen? Default 80x25 - -listm: call mode_table # List mode table -listm0: leaw name_bann, %si # Print adapter name - call prtstr - movw card_name, %si - orw %si, %si - jnz an2 - - movb adapter, %al - leaw old_name, %si - orb %al, %al - jz an1 - - leaw ega_name, %si - decb %al - jz an1 - - leaw vga_name, %si - jmp an1 - -an2: call prtstr - leaw svga_name, %si -an1: call prtstr - leaw listhdr, %si # Table header - call prtstr - movb $0x30, %dl # DL holds mode number - leaw modelist, %si -lm1: cmpw $ASK_VGA, (%si) # End? - jz lm2 - - movb %dl, %al # Menu selection number - call prtchr - call prtsp2 - lodsw - call prthw # Mode ID - call prtsp2 - movb 0x1(%si), %al - call prtdec # Rows - movb $0x78, %al # the letter 'x' - call prtchr - lodsw - call prtdec # Columns - movb $0x0d, %al # New line - call prtchr - movb $0x0a, %al - call prtchr - incb %dl # Next character - cmpb $0x3a, %dl - jnz lm1 - - movb $0x61, %dl - jmp lm1 - -lm2: leaw prompt, %si # Mode prompt - call prtstr - leaw edit_buf, %di # Editor buffer -lm3: call getkey - cmpb $0x0d, %al # Enter? - jz lment - - cmpb $0x08, %al # Backspace? - jz lmbs - - cmpb $0x20, %al # Printable? - jc lm3 - - cmpw $edit_buf+4, %di # Enough space? - jz lm3 - - stosb - call prtchr - jmp lm3 - -lmbs: cmpw $edit_buf, %di # Backspace - jz lm3 - - decw %di - movb $0x08, %al - call prtchr - call prtspc - movb $0x08, %al - call prtchr - jmp lm3 - -lment: movb $0, (%di) - leaw crlft, %si - call prtstr - leaw edit_buf, %si - cmpb $0, (%si) # Empty string = default mode - jz lmdef - - cmpb $0, 1(%si) # One character = menu selection - jz mnusel - - cmpw $0x6373, (%si) # "scan" => mode scanning - jnz lmhx - - cmpw $0x6e61, 2(%si) - jz lmscan - -lmhx: xorw %bx, %bx # Else => mode ID in hex -lmhex: lodsb - orb %al, %al - jz lmuse1 - - subb $0x30, %al - jc lmbad - - cmpb $10, %al - jc lmhx1 - - subb $7, %al - andb $0xdf, %al - cmpb $10, %al - jc lmbad - - cmpb $16, %al - jnc lmbad - -lmhx1: shlw $4, %bx - orb %al, %bl - jmp lmhex - -lmuse1: movw %bx, %ax - jmp lmuse - -mnusel: lodsb # Menu selection - xorb %ah, %ah - subb $0x30, %al - jc lmbad - - cmpb $10, %al - jc lmuse - - cmpb $0x61-0x30, %al - jc lmbad - - subb $0x61-0x30-10, %al - cmpb $36, %al - jnc lmbad - -lmuse: call mode_set - jc lmdef - -lmbad: leaw unknt, %si - call prtstr - jmp lm2 -lmscan: cmpb $0, adapter # Scanning only on EGA/VGA - jz lmbad - - movw $0, mt_end # Scanning of modes is - movb $1, scanning # done as new autodetection. - call mode_table - jmp listm0 -lmdef: ret - -# Additional parts of mode_set... (relative jumps, you know) -setv7: # Video7 extended modes - DO_STORE - subb $VIDEO_FIRST_V7>>8, %bh - movw $0x6f05, %ax - int $0x10 - stc - ret - -_setrec: jmp setrec # Ugly... -_set_80x25: jmp set_80x25 - -# Aliases for backward compatibility. -setalias: - movw $VIDEO_80x25, %ax - incw %bx - jz mode_set - - movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al - incw %bx - jnz setbad # Fall-through! - -# Setting of user mode (AX=mode ID) => CF=success -mode_set: - movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S - movw %ax, %bx - cmpb $0xff, %ah - jz setalias - - testb $VIDEO_RECALC>>8, %ah - jnz _setrec - - cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah - jnc setres - - cmpb $VIDEO_FIRST_SPECIAL>>8, %ah - jz setspc - - cmpb $VIDEO_FIRST_V7>>8, %ah - jz setv7 - - cmpb $VIDEO_FIRST_VESA>>8, %ah - jnc check_vesa - - orb %ah, %ah - jz setmenu - - decb %ah - jz setbios - -setbad: clc - movb $0, do_restore # The screen needn't be restored - ret - -setvesa: - DO_STORE - subb $VIDEO_FIRST_VESA>>8, %bh - movw $0x4f02, %ax # VESA BIOS mode set call - int $0x10 - cmpw $0x004f, %ax # AL=4f if implemented - jnz setbad # AH=0 if OK - - stc - ret - -setbios: - DO_STORE - int $0x10 # Standard BIOS mode set call - pushw %bx - movb $0x0f, %ah # Check if really set - int $0x10 - popw %bx - cmpb %bl, %al - jnz setbad - - stc - ret - -setspc: xorb %bh, %bh # Set special mode - cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl - jnc setbad - - addw %bx, %bx - jmp *spec_inits(%bx) - -setmenu: - orb %al, %al # 80x25 is an exception - jz _set_80x25 - - pushw %bx # Set mode chosen from menu - call mode_table # Build the mode table - popw %ax - shlw $2, %ax - addw %ax, %si - cmpw %di, %si - jnc setbad - - movw (%si), %ax # Fetch mode ID -_m_s: jmp mode_set - -setres: pushw %bx # Set mode chosen by resolution - call mode_table - popw %bx - xchgb %bl, %bh -setr1: lodsw - cmpw $ASK_VGA, %ax # End of the list? - jz setbad - - lodsw - cmpw %bx, %ax - jnz setr1 - - movw -4(%si), %ax # Fetch mode ID - jmp _m_s - -check_vesa: -#ifdef CONFIG_FIRMWARE_EDID - leaw modelist+1024, %di - movw $0x4f00, %ax - int $0x10 - cmpw $0x004f, %ax - jnz setbad - - movw 4(%di), %ax - movw %ax, vbe_version -#endif - leaw modelist+1024, %di - subb $VIDEO_FIRST_VESA>>8, %bh - movw %bx, %cx # Get mode information structure - movw $0x4f01, %ax - int $0x10 - addb $VIDEO_FIRST_VESA>>8, %bh - cmpw $0x004f, %ax - jnz setbad - - movb (%di), %al # Check capabilities. - andb $0x19, %al - cmpb $0x09, %al - jz setvesa # This is a text mode - - movb (%di), %al # Check capabilities. - andb $0x99, %al - cmpb $0x99, %al - jnz _setbad # Doh! No linear frame buffer. - - subb $VIDEO_FIRST_VESA>>8, %bh - orw $0x4000, %bx # Use linear frame buffer - movw $0x4f02, %ax # VESA BIOS mode set call - int $0x10 - cmpw $0x004f, %ax # AL=4f if implemented - jnz _setbad # AH=0 if OK - - movb $1, graphic_mode # flag graphic mode - movb $0, do_restore # no screen restore - stc - ret - -_setbad: jmp setbad # Ugly... - -# Recalculate vertical display end registers -- this fixes various -# inconsistencies of extended modes on many adapters. Called when -# the VIDEO_RECALC flag is set in the mode ID. - -setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode - call mode_set - jnc rct3 - - movw %gs:(0x485), %ax # Font size in pixels - movb %gs:(0x484), %bl # Number of rows - incb %bl - mulb %bl # Number of visible - decw %ax # scan lines - 1 - movw $0x3d4, %dx - movw %ax, %bx - movb $0x12, %al # Lower 8 bits - movb %bl, %ah - outw %ax, %dx - movb $0x07, %al # Bits 8 and 9 in the overflow register - call inidx - xchgb %al, %ah - andb $0xbd, %ah - shrb %bh - jnc rct1 - orb $0x02, %ah -rct1: shrb %bh - jnc rct2 - orb $0x40, %ah -rct2: movb $0x07, %al - outw %ax, %dx - stc -rct3: ret - -# Table of routines for setting of the special modes. -spec_inits: - .word set_80x25 - .word set_8pixel - .word set_80x43 - .word set_80x28 - .word set_current - .word set_80x30 - .word set_80x34 - .word set_80x60 - .word set_gfx - -# Set the 80x25 mode. If already set, do nothing. -set_80x25: - movw $0x5019, force_size # Override possibly broken BIOS -use_80x25: -#ifdef CONFIG_VIDEO_400_HACK - movw $0x1202, %ax # Force 400 scan lines - movb $0x30, %bl - int $0x10 -#else - movb $0x0f, %ah # Get current mode ID - int $0x10 - cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available - jz st80 # on CGA/MDA/HGA and is also available on EGAM - - cmpw $0x5003, %ax # Unknown mode, force 80x25 color - jnz force3 - -st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25 - jz set80 - - movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc. - orb %al, %al # Some buggy BIOS'es set 0 rows - jz set80 - - cmpb $24, %al # It's hopefully correct - jz set80 -#endif /* CONFIG_VIDEO_400_HACK */ -force3: DO_STORE - movw $0x0003, %ax # Forced set - int $0x10 -set80: stc - ret - -# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls. -set_8pixel: - DO_STORE - call use_80x25 # The base is 80x25 -set_8pt: - movw $0x1112, %ax # Use 8x8 font - xorb %bl, %bl - int $0x10 - movw $0x1200, %ax # Use alternate print screen - movb $0x20, %bl - int $0x10 - movw $0x1201, %ax # Turn off cursor emulation - movb $0x34, %bl - int $0x10 - movb $0x01, %ah # Define cursor scan lines 6-7 - movw $0x0607, %cx - int $0x10 -set_current: - stc - ret - -# Set the 80x28 mode. This mode works on all VGA's, because it's a standard -# 80x25 mode with 14-point fonts instead of 16-point. -set_80x28: - DO_STORE - call use_80x25 # The base is 80x25 -set14: movw $0x1111, %ax # Use 9x14 font - xorb %bl, %bl - int $0x10 - movb $0x01, %ah # Define cursor scan lines 11-12 - movw $0x0b0c, %cx - int $0x10 - stc - ret - -# Set the 80x43 mode. This mode is works on all VGA's. -# It's a 350-scanline mode with 8-pixel font. -set_80x43: - DO_STORE - movw $0x1201, %ax # Set 350 scans - movb $0x30, %bl - int $0x10 - movw $0x0003, %ax # Reset video mode - int $0x10 - jmp set_8pt # Use 8-pixel font - -# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font. -set_80x30: - call use_80x25 # Start with real 80x25 - DO_STORE - movw $0x3cc, %dx # Get CRTC port - inb %dx, %al - movb $0xd4, %dl - rorb %al # Mono or color? - jc set48a - - movb $0xb4, %dl -set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7) - call outidx - movw $0x0b06, %ax # Vertical total - call outidx - movw $0x3e07, %ax # (Vertical) overflow - call outidx - movw $0xea10, %ax # Vertical sync start - call outidx - movw $0xdf12, %ax # Vertical display end - call outidx - movw $0xe715, %ax # Vertical blank start - call outidx - movw $0x0416, %ax # Vertical blank end - call outidx - pushw %dx - movb $0xcc, %dl # Misc output register (read) - inb %dx, %al - movb $0xc2, %dl # (write) - andb $0x0d, %al # Preserve clock select bits and color bit - orb $0xe2, %al # Set correct sync polarity - outb %al, %dx - popw %dx - movw $0x501e, force_size - stc # That's all. - ret - -# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font. -set_80x34: - call set_80x30 # Set 480 scans - call set14 # And 14-pt font - movw $0xdb12, %ax # VGA vertical display end - movw $0x5022, force_size -setvde: call outidx - stc - ret - -# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font. -set_80x60: - call set_80x30 # Set 480 scans - call set_8pt # And 8-pt font - movw $0xdf12, %ax # VGA vertical display end - movw $0x503c, force_size - jmp setvde - -# Special hack for ThinkPad graphics -set_gfx: -#ifdef CONFIG_VIDEO_GFX_HACK - movw $VIDEO_GFX_BIOS_AX, %ax - movw $VIDEO_GFX_BIOS_BX, %bx - int $0x10 - movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size - stc -#endif - ret - -#ifdef CONFIG_VIDEO_RETAIN - -# Store screen contents to temporary buffer. -store_screen: - cmpb $0, do_restore # Already stored? - jnz stsr - - testb $CAN_USE_HEAP, loadflags # Have we space for storing? - jz stsr - - pushw %ax - pushw %bx - pushw force_size # Don't force specific size - movw $0, force_size - call mode_params # Obtain params of current mode - popw force_size - movb %fs:(PARAM_VIDEO_LINES), %ah - movb %fs:(PARAM_VIDEO_COLS), %al - movw %ax, %bx # BX=dimensions - mulb %ah - movw %ax, %cx # CX=number of characters - addw %ax, %ax # Calculate image size - addw $modelist+1024+4, %ax - cmpw heap_end_ptr, %ax - jnc sts1 # Unfortunately, out of memory - - movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params - leaw modelist+1024, %di - stosw - movw %bx, %ax - stosw - pushw %ds # Store the screen - movw video_segment, %ds - xorw %si, %si - rep - movsw - popw %ds - incb do_restore # Screen will be restored later -sts1: popw %bx - popw %ax -stsr: ret - -# Restore screen contents from temporary buffer. -restore_screen: - cmpb $0, do_restore # Has the screen been stored? - jz res1 - - call mode_params # Get parameters of current mode - movb %fs:(PARAM_VIDEO_LINES), %cl - movb %fs:(PARAM_VIDEO_COLS), %ch - leaw modelist+1024, %si # Screen buffer - lodsw # Set cursor position - movw %ax, %dx - cmpb %cl, %dh - jc res2 - - movb %cl, %dh - decb %dh -res2: cmpb %ch, %dl - jc res3 - - movb %ch, %dl - decb %dl -res3: movb $0x02, %ah - movb $0x00, %bh - int $0x10 - lodsw # Display size - movb %ah, %dl # DL=number of lines - movb $0, %ah # BX=phys. length of orig. line - movw %ax, %bx - cmpb %cl, %dl # Too many? - jc res4 - - pushw %ax - movb %dl, %al - subb %cl, %al - mulb %bl - addw %ax, %si - addw %ax, %si - popw %ax - movb %cl, %dl -res4: cmpb %ch, %al # Too wide? - jc res5 - - movb %ch, %al # AX=width of src. line -res5: movb $0, %cl - xchgb %ch, %cl - movw %cx, %bp # BP=width of dest. line - pushw %es - movw video_segment, %es - xorw %di, %di # Move the data - addw %bx, %bx # Convert BX and BP to _bytes_ - addw %bp, %bp -res6: pushw %si - pushw %di - movw %ax, %cx - rep - movsw - popw %di - popw %si - addw %bp, %di - addw %bx, %si - decb %dl - jnz res6 - - popw %es # Done -res1: ret -#endif /* CONFIG_VIDEO_RETAIN */ - -# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port) -outidx: outb %al, %dx - pushw %ax - movb %ah, %al - incw %dx - outb %al, %dx - decw %dx - popw %ax - ret - -# Build the table of video modes (stored after the setup.S code at the -# `modelist' label. Each video mode record looks like: -# .word MODE-ID (our special mode ID (see above)) -# .byte rows (number of rows) -# .byte columns (number of columns) -# Returns address of the end of the table in DI, the end is marked -# with a ASK_VGA ID. -mode_table: - movw mt_end, %di # Already filled? - orw %di, %di - jnz mtab1x - - leaw modelist, %di # Store standard modes: - movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL) - stosl - movb adapter, %al # CGA/MDA/HGA -- no more modes - orb %al, %al - jz mtabe - - decb %al - jnz mtabv - - movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode - stosl - jmp mtabe - -mtab1x: jmp mtab1 - -mtabv: leaw vga_modes, %si # All modes for std VGA - movw $vga_modes_end-vga_modes, %cx - rep # I'm unable to use movsw as I don't know how to store a half - movsb # of the expression above to cx without using explicit shr. - - cmpb $0, scanning # Mode scan requested? - jz mscan1 - - call mode_scan -mscan1: - -#ifdef CONFIG_VIDEO_LOCAL - call local_modes -#endif /* CONFIG_VIDEO_LOCAL */ - -#ifdef CONFIG_VIDEO_VESA - call vesa_modes # Detect VESA VGA modes -#endif /* CONFIG_VIDEO_VESA */ - -#ifdef CONFIG_VIDEO_SVGA - cmpb $0, scanning # Bypass when scanning - jnz mscan2 - - call svga_modes # Detect SVGA cards & modes -mscan2: -#endif /* CONFIG_VIDEO_SVGA */ - -mtabe: - -#ifdef CONFIG_VIDEO_COMPACT - leaw modelist, %si - movw %di, %dx - movw %si, %di -cmt1: cmpw %dx, %si # Scan all modes - jz cmt2 - - leaw modelist, %bx # Find in previous entries - movw 2(%si), %cx -cmt3: cmpw %bx, %si - jz cmt4 - - cmpw 2(%bx), %cx # Found => don't copy this entry - jz cmt5 - - addw $4, %bx - jmp cmt3 - -cmt4: movsl # Copy entry - jmp cmt1 - -cmt5: addw $4, %si # Skip entry - jmp cmt1 - -cmt2: -#endif /* CONFIG_VIDEO_COMPACT */ - - movw $ASK_VGA, (%di) # End marker - movw %di, mt_end -mtab1: leaw modelist, %si # SI=mode list, DI=list end -ret0: ret - -# Modes usable on all standard VGAs -vga_modes: - .word VIDEO_8POINT - .word 0x5032 # 80x50 - .word VIDEO_80x43 - .word 0x502b # 80x43 - .word VIDEO_80x28 - .word 0x501c # 80x28 - .word VIDEO_80x30 - .word 0x501e # 80x30 - .word VIDEO_80x34 - .word 0x5022 # 80x34 - .word VIDEO_80x60 - .word 0x503c # 80x60 -#ifdef CONFIG_VIDEO_GFX_HACK - .word VIDEO_GFX_HACK - .word VIDEO_GFX_DUMMY_RESOLUTION -#endif - -vga_modes_end: -# Detect VESA modes. - -#ifdef CONFIG_VIDEO_VESA -vesa_modes: - cmpb $2, adapter # VGA only - jnz ret0 - - movw %di, %bp # BP=original mode table end - addw $0x200, %di # Buffer space - movw $0x4f00, %ax # VESA Get card info call - int $0x10 - movw %bp, %di - cmpw $0x004f, %ax # Successful? - jnz ret0 - - cmpw $0x4556, 0x200(%di) - jnz ret0 - - cmpw $0x4153, 0x202(%di) - jnz ret0 - - movw $vesa_name, card_name # Set name to "VESA VGA" - pushw %gs - lgsw 0x20e(%di), %si # GS:SI=mode list - movw $128, %cx # Iteration limit -vesa1: -# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst. -# XXX: lodsw %gs:(%si), %ax # Get next mode in the list - gs; lodsw - cmpw $0xffff, %ax # End of the table? - jz vesar - - cmpw $0x0080, %ax # Check validity of mode ID - jc vesa2 - - orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff - jz vesan # Certain BIOSes report 0x80-0xff! - - cmpw $0x0800, %ax - jnc vesae - -vesa2: pushw %cx - movw %ax, %cx # Get mode information structure - movw $0x4f01, %ax - int $0x10 - movw %cx, %bx # BX=mode number - addb $VIDEO_FIRST_VESA>>8, %bh - popw %cx - cmpw $0x004f, %ax - jnz vesan # Don't report errors (buggy BIOSES) - - movb (%di), %al # Check capabilities. We require - andb $0x19, %al # a color text mode. - cmpb $0x09, %al - jnz vesan - - cmpw $0xb800, 8(%di) # Standard video memory address required - jnz vesan - - testb $2, (%di) # Mode characteristics supplied? - movw %bx, (%di) # Store mode number - jz vesa3 - - xorw %dx, %dx - movw 0x12(%di), %bx # Width - orb %bh, %bh - jnz vesan - - movb %bl, 0x3(%di) - movw 0x14(%di), %ax # Height - orb %ah, %ah - jnz vesan - - movb %al, 2(%di) - mulb %bl - cmpw $8193, %ax # Small enough for Linux console driver? - jnc vesan - - jmp vesaok - -vesa3: subw $0x8108, %bx # This mode has no detailed info specified, - jc vesan # so it must be a standard VESA mode. - - cmpw $5, %bx - jnc vesan - - movw vesa_text_mode_table(%bx), %ax - movw %ax, 2(%di) -vesaok: addw $4, %di # The mode is valid. Store it. -vesan: loop vesa1 # Next mode. Limit exceeded => error -vesae: leaw vesaer, %si - call prtstr - movw %bp, %di # Discard already found modes. -vesar: popw %gs - ret - -# Dimensions of standard VESA text modes -vesa_text_mode_table: - .byte 60, 80 # 0108 - .byte 25, 132 # 0109 - .byte 43, 132 # 010A - .byte 50, 132 # 010B - .byte 60, 132 # 010C -#endif /* CONFIG_VIDEO_VESA */ - -# Scan for video modes. A bit dirty, but should work. -mode_scan: - movw $0x0100, %cx # Start with mode 0 -scm1: movb $0, %ah # Test the mode - movb %cl, %al - int $0x10 - movb $0x0f, %ah - int $0x10 - cmpb %cl, %al - jnz scm2 # Mode not set - - movw $0x3c0, %dx # Test if it's a text mode - movb $0x10, %al # Mode bits - call inidx - andb $0x03, %al - jnz scm2 - - movb $0xce, %dl # Another set of mode bits - movb $0x06, %al - call inidx - shrb %al - jc scm2 - - movb $0xd4, %dl # Cursor location - movb $0x0f, %al - call inidx - orb %al, %al - jnz scm2 - - movw %cx, %ax # Ok, store the mode - stosw - movb %gs:(0x484), %al # Number of rows - incb %al - stosb - movw %gs:(0x44a), %ax # Number of columns - stosb -scm2: incb %cl - jns scm1 - - movw $0x0003, %ax # Return back to mode 3 - int $0x10 - ret - -tstidx: outw %ax, %dx # OUT DX,AX and inidx -inidx: outb %al, %dx # Read from indexed VGA register - incw %dx # AL=index, DX=index reg port -> AL=data - inb %dx, %al - decw %dx - ret - -# Try to detect type of SVGA card and supply (usually approximate) video -# mode table for it. - -#ifdef CONFIG_VIDEO_SVGA -svga_modes: - leaw svga_table, %si # Test all known SVGA adapters -dosvga: lodsw - movw %ax, %bp # Default mode table - orw %ax, %ax - jz didsv1 - - lodsw # Pointer to test routine - pushw %si - pushw %di - pushw %es - movw $0xc000, %bx - movw %bx, %es - call *%ax # Call test routine - popw %es - popw %di - popw %si - orw %bp, %bp - jz dosvga - - movw %bp, %si # Found, copy the modes - movb svga_prefix, %ah -cpsvga: lodsb - orb %al, %al - jz didsv - - stosw - movsw - jmp cpsvga - -didsv: movw %si, card_name # Store pointer to card name -didsv1: ret - -# Table of all known SVGA cards. For each card, we store a pointer to -# a table of video modes supported by the card and a pointer to a routine -# used for testing of presence of the card. The video mode table is always -# followed by the name of the card or the chipset. -svga_table: - .word ati_md, ati_test - .word oak_md, oak_test - .word paradise_md, paradise_test - .word realtek_md, realtek_test - .word s3_md, s3_test - .word chips_md, chips_test - .word video7_md, video7_test - .word cirrus5_md, cirrus5_test - .word cirrus6_md, cirrus6_test - .word cirrus1_md, cirrus1_test - .word ahead_md, ahead_test - .word everex_md, everex_test - .word genoa_md, genoa_test - .word trident_md, trident_test - .word tseng_md, tseng_test - .word 0 - -# Test routines and mode tables: - -# S3 - The test algorithm was taken from the SuperProbe package -# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org -s3_test: - movw $0x0f35, %cx # we store some constants in cl/ch - movw $0x03d4, %dx - movb $0x38, %al - call inidx - movb %al, %bh # store current CRT-register 0x38 - movw $0x0038, %ax - call outidx # disable writing to special regs - movb %cl, %al # check whether we can write special reg 0x35 - call inidx - movb %al, %bl # save the current value of CRT reg 0x35 - andb $0xf0, %al # clear bits 0-3 - movb %al, %ah - movb %cl, %al # and write it to CRT reg 0x35 - call outidx - call inidx # now read it back - andb %ch, %al # clear the upper 4 bits - jz s3_2 # the first test failed. But we have a - - movb %bl, %ah # second chance - movb %cl, %al - call outidx - jmp s3_1 # do the other tests - -s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35 - orb %bl, %ah # set the upper 4 bits of ah with the orig value - call outidx # write ... - call inidx # ... and reread - andb %cl, %al # turn off the upper 4 bits - pushw %ax - movb %bl, %ah # restore old value in register 0x35 - movb %cl, %al - call outidx - popw %ax - cmpb %ch, %al # setting lower 4 bits was successful => bad - je no_s3 # writing is allowed => this is not an S3 - -s3_1: movw $0x4838, %ax # allow writing to special regs by putting - call outidx # magic number into CRT-register 0x38 - movb %cl, %al # check whether we can write special reg 0x35 - call inidx - movb %al, %bl - andb $0xf0, %al - movb %al, %ah - movb %cl, %al - call outidx - call inidx - andb %ch, %al - jnz no_s3 # no, we can't write => no S3 - - movw %cx, %ax - orb %bl, %ah - call outidx - call inidx - andb %ch, %al - pushw %ax - movb %bl, %ah # restore old value in register 0x35 - movb %cl, %al - call outidx - popw %ax - cmpb %ch, %al - jne no_s31 # writing not possible => no S3 - movb $0x30, %al - call inidx # now get the S3 id ... - leaw idS3, %di - movw $0x10, %cx - repne - scasb - je no_s31 - - movb %bh, %ah - movb $0x38, %al - jmp s3rest - -no_s3: movb $0x35, %al # restore CRT register 0x35 - movb %bl, %ah - call outidx -no_s31: xorw %bp, %bp # Detection failed -s3rest: movb %bh, %ah - movb $0x38, %al # restore old value of CRT register 0x38 - jmp outidx - -idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 - .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 - -s3_md: .byte 0x54, 0x2b, 0x84 - .byte 0x55, 0x19, 0x84 - .byte 0 - .ascii "S3" - .byte 0 - -# ATI cards. -ati_test: - leaw idati, %si - movw $0x31, %di - movw $0x09, %cx - repe - cmpsb - je atiok - - xorw %bp, %bp -atiok: ret - -idati: .ascii "761295520" - -ati_md: .byte 0x23, 0x19, 0x84 - .byte 0x33, 0x2c, 0x84 - .byte 0x22, 0x1e, 0x64 - .byte 0x21, 0x19, 0x64 - .byte 0x58, 0x21, 0x50 - .byte 0x5b, 0x1e, 0x50 - .byte 0 - .ascii "ATI" - .byte 0 - -# AHEAD -ahead_test: - movw $0x200f, %ax - movw $0x3ce, %dx - outw %ax, %dx - incw %dx - inb %dx, %al - cmpb $0x20, %al - je isahed - - cmpb $0x21, %al - je isahed - - xorw %bp, %bp -isahed: ret - -ahead_md: - .byte 0x22, 0x2c, 0x84 - .byte 0x23, 0x19, 0x84 - .byte 0x24, 0x1c, 0x84 - .byte 0x2f, 0x32, 0xa0 - .byte 0x32, 0x22, 0x50 - .byte 0x34, 0x42, 0x50 - .byte 0 - .ascii "Ahead" - .byte 0 - -# Chips & Tech. -chips_test: - movw $0x3c3, %dx - inb %dx, %al - orb $0x10, %al - outb %al, %dx - movw $0x104, %dx - inb %dx, %al - movb %al, %bl - movw $0x3c3, %dx - inb %dx, %al - andb $0xef, %al - outb %al, %dx - cmpb $0xa5, %bl - je cantok - - xorw %bp, %bp -cantok: ret - -chips_md: - .byte 0x60, 0x19, 0x84 - .byte 0x61, 0x32, 0x84 - .byte 0 - .ascii "Chips & Technologies" - .byte 0 - -# Cirrus Logic 5X0 -cirrus1_test: - movw $0x3d4, %dx - movb $0x0c, %al - outb %al, %dx - incw %dx - inb %dx, %al - movb %al, %bl - xorb %al, %al - outb %al, %dx - decw %dx - movb $0x1f, %al - outb %al, %dx - incw %dx - inb %dx, %al - movb %al, %bh - xorb %ah, %ah - shlb $4, %al - movw %ax, %cx - movb %bh, %al - shrb $4, %al - addw %ax, %cx - shlw $8, %cx - addw $6, %cx - movw %cx, %ax - movw $0x3c4, %dx - outw %ax, %dx - incw %dx - inb %dx, %al - andb %al, %al - jnz nocirr - - movb %bh, %al - outb %al, %dx - inb %dx, %al - cmpb $0x01, %al - je iscirr - -nocirr: xorw %bp, %bp -iscirr: movw $0x3d4, %dx - movb %bl, %al - xorb %ah, %ah - shlw $8, %ax - addw $0x0c, %ax - outw %ax, %dx - ret - -cirrus1_md: - .byte 0x1f, 0x19, 0x84 - .byte 0x20, 0x2c, 0x84 - .byte 0x22, 0x1e, 0x84 - .byte 0x31, 0x25, 0x64 - .byte 0 - .ascii "Cirrus Logic 5X0" - .byte 0 - -# Cirrus Logic 54XX -cirrus5_test: - movw $0x3c4, %dx - movb $6, %al - call inidx - movb %al, %bl # BL=backup - movw $6, %ax - call tstidx - cmpb $0x0f, %al - jne c5fail - - movw $0x1206, %ax - call tstidx - cmpb $0x12, %al - jne c5fail - - movb $0x1e, %al - call inidx - movb %al, %bh - movb %bh, %ah - andb $0xc0, %ah - movb $0x1e, %al - call tstidx - andb $0x3f, %al - jne c5xx - - movb $0x1e, %al - movb %bh, %ah - orb $0x3f, %ah - call tstidx - xorb $0x3f, %al - andb $0x3f, %al -c5xx: pushf - movb $0x1e, %al - movb %bh, %ah - outw %ax, %dx - popf - je c5done - -c5fail: xorw %bp, %bp -c5done: movb $6, %al - movb %bl, %ah - outw %ax, %dx - ret - -cirrus5_md: - .byte 0x14, 0x19, 0x84 - .byte 0x54, 0x2b, 0x84 - .byte 0 - .ascii "Cirrus Logic 54XX" - .byte 0 - -# Cirrus Logic 64XX -- no known extra modes, but must be identified, because -# it's misidentified by the Ahead test. -cirrus6_test: - movw $0x3ce, %dx - movb $0x0a, %al - call inidx - movb %al, %bl # BL=backup - movw $0xce0a, %ax - call tstidx - orb %al, %al - jne c2fail - - movw $0xec0a, %ax - call tstidx - cmpb $0x01, %al - jne c2fail - - movb $0xaa, %al - call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's. - shrb $4, %al - subb $4, %al - jz c6done - - decb %al - jz c6done - - subb $2, %al - jz c6done - - decb %al - jz c6done - -c2fail: xorw %bp, %bp -c6done: movb $0x0a, %al - movb %bl, %ah - outw %ax, %dx - ret - -cirrus6_md: - .byte 0 - .ascii "Cirrus Logic 64XX" - .byte 0 - -# Everex / Trident -everex_test: - movw $0x7000, %ax - xorw %bx, %bx - int $0x10 - cmpb $0x70, %al - jne noevrx - - shrw $4, %dx - cmpw $0x678, %dx - je evtrid - - cmpw $0x236, %dx - jne evrxok - -evtrid: leaw trident_md, %bp -evrxok: ret - -noevrx: xorw %bp, %bp - ret - -everex_md: - .byte 0x03, 0x22, 0x50 - .byte 0x04, 0x3c, 0x50 - .byte 0x07, 0x2b, 0x64 - .byte 0x08, 0x4b, 0x64 - .byte 0x0a, 0x19, 0x84 - .byte 0x0b, 0x2c, 0x84 - .byte 0x16, 0x1e, 0x50 - .byte 0x18, 0x1b, 0x64 - .byte 0x21, 0x40, 0xa0 - .byte 0x40, 0x1e, 0x84 - .byte 0 - .ascii "Everex/Trident" - .byte 0 - -# Genoa. -genoa_test: - leaw idgenoa, %si # Check Genoa 'clues' - xorw %ax, %ax - movb %es:(0x37), %al - movw %ax, %di - movw $0x04, %cx - decw %si - decw %di -l1: incw %si - incw %di - movb (%si), %al - testb %al, %al - jz l2 - - cmpb %es:(%di), %al -l2: loope l1 - orw %cx, %cx - je isgen - - xorw %bp, %bp -isgen: ret - -idgenoa: .byte 0x77, 0x00, 0x99, 0x66 - -genoa_md: - .byte 0x58, 0x20, 0x50 - .byte 0x5a, 0x2a, 0x64 - .byte 0x60, 0x19, 0x84 - .byte 0x61, 0x1d, 0x84 - .byte 0x62, 0x20, 0x84 - .byte 0x63, 0x2c, 0x84 - .byte 0x64, 0x3c, 0x84 - .byte 0x6b, 0x4f, 0x64 - .byte 0x72, 0x3c, 0x50 - .byte 0x74, 0x42, 0x50 - .byte 0x78, 0x4b, 0x64 - .byte 0 - .ascii "Genoa" - .byte 0 - -# OAK -oak_test: - leaw idoakvga, %si - movw $0x08, %di - movw $0x08, %cx - repe - cmpsb - je isoak - - xorw %bp, %bp -isoak: ret - -idoakvga: .ascii "OAK VGA " - -oak_md: .byte 0x4e, 0x3c, 0x50 - .byte 0x4f, 0x3c, 0x84 - .byte 0x50, 0x19, 0x84 - .byte 0x51, 0x2b, 0x84 - .byte 0 - .ascii "OAK" - .byte 0 - -# WD Paradise. -paradise_test: - leaw idparadise, %si - movw $0x7d, %di - movw $0x04, %cx - repe - cmpsb - je ispara - - xorw %bp, %bp -ispara: ret - -idparadise: .ascii "VGA=" - -paradise_md: - .byte 0x41, 0x22, 0x50 - .byte 0x47, 0x1c, 0x84 - .byte 0x55, 0x19, 0x84 - .byte 0x54, 0x2c, 0x84 - .byte 0 - .ascii "Paradise" - .byte 0 - -# Trident. -trident_test: - movw $0x3c4, %dx - movb $0x0e, %al - outb %al, %dx - incw %dx - inb %dx, %al - xchgb %al, %ah - xorb %al, %al - outb %al, %dx - inb %dx, %al - xchgb %ah, %al - movb %al, %bl # Strange thing ... in the book this wasn't - andb $0x02, %bl # necessary but it worked on my card which - jz setb2 # is a trident. Without it the screen goes - # blurred ... - andb $0xfd, %al - jmp clrb2 - -setb2: orb $0x02, %al -clrb2: outb %al, %dx - andb $0x0f, %ah - cmpb $0x02, %ah - je istrid - - xorw %bp, %bp -istrid: ret - -trident_md: - .byte 0x50, 0x1e, 0x50 - .byte 0x51, 0x2b, 0x50 - .byte 0x52, 0x3c, 0x50 - .byte 0x57, 0x19, 0x84 - .byte 0x58, 0x1e, 0x84 - .byte 0x59, 0x2b, 0x84 - .byte 0x5a, 0x3c, 0x84 - .byte 0 - .ascii "Trident" - .byte 0 - -# Tseng. -tseng_test: - movw $0x3cd, %dx - inb %dx, %al # Could things be this simple ! :-) - movb %al, %bl - movb $0x55, %al - outb %al, %dx - inb %dx, %al - movb %al, %ah - movb %bl, %al - outb %al, %dx - cmpb $0x55, %ah - je istsen - -isnot: xorw %bp, %bp -istsen: ret - -tseng_md: - .byte 0x26, 0x3c, 0x50 - .byte 0x2a, 0x28, 0x64 - .byte 0x23, 0x19, 0x84 - .byte 0x24, 0x1c, 0x84 - .byte 0x22, 0x2c, 0x84 - .byte 0x21, 0x3c, 0x84 - .byte 0 - .ascii "Tseng" - .byte 0 - -# Video7. -video7_test: - movw $0x3cc, %dx - inb %dx, %al - movw $0x3b4, %dx - andb $0x01, %al - jz even7 - - movw $0x3d4, %dx -even7: movb $0x0c, %al - outb %al, %dx - incw %dx - inb %dx, %al - movb %al, %bl - movb $0x55, %al - outb %al, %dx - inb %dx, %al - decw %dx - movb $0x1f, %al - outb %al, %dx - incw %dx - inb %dx, %al - movb %al, %bh - decw %dx - movb $0x0c, %al - outb %al, %dx - incw %dx - movb %bl, %al - outb %al, %dx - movb $0x55, %al - xorb $0xea, %al - cmpb %bh, %al - jne isnot - - movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching - ret - -video7_md: - .byte 0x40, 0x2b, 0x50 - .byte 0x43, 0x3c, 0x50 - .byte 0x44, 0x3c, 0x64 - .byte 0x41, 0x19, 0x84 - .byte 0x42, 0x2c, 0x84 - .byte 0x45, 0x1c, 0x84 - .byte 0 - .ascii "Video 7" - .byte 0 - -# Realtek VGA -realtek_test: - leaw idrtvga, %si - movw $0x45, %di - movw $0x0b, %cx - repe - cmpsb - je isrt - - xorw %bp, %bp -isrt: ret - -idrtvga: .ascii "REALTEK VGA" - -realtek_md: - .byte 0x1a, 0x3c, 0x50 - .byte 0x1b, 0x19, 0x84 - .byte 0x1c, 0x1e, 0x84 - .byte 0x1d, 0x2b, 0x84 - .byte 0x1e, 0x3c, 0x84 - .byte 0 - .ascii "REALTEK" - .byte 0 - -#endif /* CONFIG_VIDEO_SVGA */ - -# User-defined local mode table (VGA only) -#ifdef CONFIG_VIDEO_LOCAL -local_modes: - leaw local_mode_table, %si -locm1: lodsw - orw %ax, %ax - jz locm2 - - stosw - movsw - jmp locm1 - -locm2: ret - -# This is the table of local video modes which can be supplied manually -# by the user. Each entry consists of mode ID (word) and dimensions -# (byte for column count and another byte for row count). These modes -# are placed before all SVGA and VESA modes and override them if table -# compacting is enabled. The table must end with a zero word followed -# by NUL-terminated video adapter name. -local_mode_table: - .word 0x0100 # Example: 40x25 - .byte 25,40 - .word 0 - .ascii "Local" - .byte 0 -#endif /* CONFIG_VIDEO_LOCAL */ - -# Read a key and return the ASCII code in al, scan code in ah -getkey: xorb %ah, %ah - int $0x16 - ret - -# Read a key with a timeout of 30 seconds. -# The hardware clock is used to get the time. -getkt: call gettime - addb $30, %al # Wait 30 seconds - cmpb $60, %al - jl lminute - - subb $60, %al -lminute: - movb %al, %cl -again: movb $0x01, %ah - int $0x16 - jnz getkey # key pressed, so get it - - call gettime - cmpb %cl, %al - jne again - - movb $0x20, %al # timeout, return `space' - ret - -# Flush the keyboard buffer -flush: movb $0x01, %ah - int $0x16 - jz empty - - xorb %ah, %ah - int $0x16 - jmp flush - -empty: ret - -# Print hexadecimal number. -prthw: pushw %ax - movb %ah, %al - call prthb - popw %ax -prthb: pushw %ax - shrb $4, %al - call prthn - popw %ax - andb $0x0f, %al -prthn: cmpb $0x0a, %al - jc prth1 - - addb $0x07, %al -prth1: addb $0x30, %al - jmp prtchr - -# Print decimal number in al -prtdec: pushw %ax - pushw %cx - xorb %ah, %ah - movb $0x0a, %cl - idivb %cl - cmpb $0x09, %al - jbe lt100 - - call prtdec - jmp skip10 - -lt100: addb $0x30, %al - call prtchr -skip10: movb %ah, %al - addb $0x30, %al - call prtchr - popw %cx - popw %ax - ret - -store_edid: -#ifdef CONFIG_FIRMWARE_EDID - pushw %es # just save all registers - pushw %ax - pushw %bx - pushw %cx - pushw %dx - pushw %di - - pushw %fs - popw %es - - movl $0x13131313, %eax # memset block with 0x13 - movw $32, %cx - movw $0x140, %di - cld - rep - stosl - - cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0 - jl no_edid - - pushw %es # save ES - xorw %di, %di # Report Capability - pushw %di - popw %es # ES:DI must be 0:0 - movw $0x4f15, %ax - xorw %bx, %bx - xorw %cx, %cx - int $0x10 - popw %es # restore ES - - cmpb $0x00, %ah # call successful - jne no_edid - - cmpb $0x4f, %al # function supported - jne no_edid - - movw $0x4f15, %ax # do VBE/DDC - movw $0x01, %bx - movw $0x00, %cx - movw $0x00, %dx - movw $0x140, %di - int $0x10 - -no_edid: - popw %di # restore all registers - popw %dx - popw %cx - popw %bx - popw %ax - popw %es -#endif - ret - -# VIDEO_SELECT-only variables -mt_end: .word 0 # End of video mode table if built -edit_buf: .space 6 # Line editor buffer -card_name: .word 0 # Pointer to adapter name -scanning: .byte 0 # Performing mode scan -do_restore: .byte 0 # Screen contents altered during mode change -svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes -graphic_mode: .byte 0 # Graphic mode with a linear frame buffer -dac_size: .byte 6 # DAC bit depth -vbe_version: .word 0 # VBE bios version - -# Status messages -keymsg: .ascii "Press to see video modes available, " - .ascii " to continue or wait 30 secs" - .byte 0x0d, 0x0a, 0 - -listhdr: .byte 0x0d, 0x0a - .ascii "Mode: COLSxROWS:" - -crlft: .byte 0x0d, 0x0a, 0 - -prompt: .byte 0x0d, 0x0a - .asciz "Enter mode number or `scan': " - -unknt: .asciz "Unknown mode ID. Try again." - -badmdt: .ascii "You passed an undefined mode number." - .byte 0x0d, 0x0a, 0 - -vesaer: .ascii "Error: Scanning of VESA modes failed. Please " - .ascii "report to ." - .byte 0x0d, 0x0a, 0 - -old_name: .asciz "CGA/MDA/HGA" - -ega_name: .asciz "EGA" - -svga_name: .ascii " " - -vga_name: .asciz "VGA" - -vesa_name: .asciz "VESA" - -name_bann: .asciz "Video adapter: " -#endif /* CONFIG_VIDEO_SELECT */ - -# Other variables: -adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA -video_segment: .word 0xb800 # Video memory segment -force_size: .word 0 # Use this size instead of the one in BIOS vars --- /dev/null +++ b/arch/i386/boot/video.c @@ -0,0 +1,456 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/video.c + * + * Select video mode + */ + +#include "boot.h" +#include "video.h" +#include "vesa.h" + +/* + * Mode list variables + */ +static struct card_info cards[]; /* List of cards to probe for */ + +/* + * Common variables + */ +int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ +u16 video_segment; +int force_x, force_y; /* Don't query the BIOS for cols/rows */ + +int do_restore = 0; /* Screen contents changed during mode flip */ +int graphic_mode; /* Graphic mode with linear frame buffer */ + +static void store_cursor_position(void) +{ + u16 curpos; + u16 ax, bx; + + ax = 0x0300; + bx = 0; + asm(INT10 + : "=d" (curpos), "+a" (ax), "+b" (bx) + : : "ecx", "esi", "edi"); + + boot_params.screen_info.orig_x = curpos; + boot_params.screen_info.orig_y = curpos >> 8; +} + +static void store_video_mode(void) +{ + u16 ax, page; + + /* N.B.: the saving of the video page here is a bit silly, + since we pretty much assume page 0 everywhere. */ + ax = 0x0f00; + asm(INT10 + : "+a" (ax), "=b" (page) + : : "ecx", "edx", "esi", "edi"); + + /* Not all BIOSes are clean with respect to the top bit */ + boot_params.screen_info.orig_video_mode = ax & 0x7f; + boot_params.screen_info.orig_video_page = page; +} + +/* + * Store the video mode parameters for later usage by the kernel. + * This is done by asking the BIOS except for the rows/columns + * parameters in the default 80x25 mode -- these are set directly, + * because some very obscure BIOSes supply insane values. + */ +static void store_mode_params(void) +{ + u16 font_size; + int x, y; + + /* For graphics mode, it is up to the mode-setting driver + (currently only video-vesa.c) to store the parameters */ + if (graphic_mode) + return; + + store_cursor_position(); + store_video_mode(); + + if (boot_params.screen_info.orig_video_mode == 0x07) { + /* MDA, HGC, or VGA in monochrome mode */ + video_segment = 0xb000; + } else { + /* CGA, EGA, VGA and so forth */ + video_segment = 0xb800; + } + + set_fs(0); + font_size = rdfs16(0x485); /* Font size, BIOS area */ + boot_params.screen_info.orig_video_points = font_size; + + x = rdfs16(0x44a); + y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1; + + if (force_x) + x = force_x; + if (force_y) + y = force_y; + + boot_params.screen_info.orig_video_cols = x; + boot_params.screen_info.orig_video_lines = y; +} + +/* Probe the video drivers and have them generate their mode lists. */ +static void probe_cards(int unsafe) +{ + struct card_info *card; + static u8 probed[2]; + + if (probed[unsafe]) + return; + + probed[unsafe] = 1; + + for (card = video_cards; card < video_cards_end; card++) { + if (card->unsafe == unsafe) { + if (card->probe) + card->nmodes = card->probe(); + else + card->nmodes = 0; + } + } +} + +/* Test if a mode is defined */ +int mode_defined(u16 mode) +{ + struct card_info *card; + struct mode_info *mi; + int i; + + for (card = video_cards; card < video_cards_end; card++) { + mi = card->modes; + for (i = 0; i < card->nmodes; i++, mi++) { + if (mi->mode == mode) + return 1; + } + } + + return 0; +} + +/* Set mode (without recalc) */ +static int raw_set_mode(u16 mode) +{ + int nmode, i; + struct card_info *card; + struct mode_info *mi; + + /* Drop the recalc bit if set */ + mode &= ~VIDEO_RECALC; + + /* Scan for mode based on fixed ID, position, or resolution */ + nmode = 0; + for (card = video_cards; card < video_cards_end; card++) { + mi = card->modes; + for (i = 0; i < card->nmodes; i++, mi++) { + int visible = mi->x || mi->y; + + if ((mode == nmode && visible) || + mode == mi->mode || + mode == (mi->y << 8)+mi->x) + return card->set_mode(mi); + + if (visible) + nmode++; + } + } + + /* Nothing found? Is it an "exceptional" (unprobed) mode? */ + for (card = video_cards; card < video_cards_end; card++) { + if (mode >= card->xmode_first && + mode < card->xmode_first+card->xmode_n) { + struct mode_info mix; + mix.mode = mode; + mix.x = mix.y = 0; + return card->set_mode(&mix); + } + } + + /* Otherwise, failure... */ + return -1; +} + +/* + * Recalculate the vertical video cutoff (hack!) + */ +static void vga_recalc_vertical(void) +{ + unsigned int font_size, rows; + u16 crtc; + u8 ov; + + set_fs(0); + font_size = rdfs8(0x485); /* BIOS: font size (pixels) */ + rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */ + + rows *= font_size; /* Visible scan lines */ + rows--; /* ... minus one */ + + crtc = vga_crtc(); + + out_idx((u8)rows, crtc, 0x12); /* Lower height register */ + ov = in_idx(crtc, 0x07); /* Overflow register */ + ov &= 0xbd; + ov |= (rows >> (8-1)) & 0x02; + ov |= (rows >> (9-6)) & 0x40; + out_idx(ov, crtc, 0x07); +} + +/* Set mode (with recalc if specified) */ +static int set_mode(u16 mode) +{ + int rv; + + /* Very special mode numbers... */ + if (mode == VIDEO_CURRENT_MODE) + return 0; /* Nothing to do... */ + else if (mode == NORMAL_VGA) + mode = VIDEO_80x25; + else if (mode == EXTENDED_VGA) + mode = VIDEO_8POINT; + + rv = raw_set_mode(mode); + if (rv) + return rv; + + if (mode & VIDEO_RECALC) + vga_recalc_vertical(); + + return 0; +} + +static unsigned int get_entry(void) +{ + char entry_buf[4]; + int i, len = 0; + int key; + unsigned int v; + + do { + key = getchar(); + + if (key == '\b') { + if (len > 0) { + puts("\b \b"); + len--; + } + } else if ((key >= '0' && key <= '9') || + (key >= 'A' && key <= 'Z') || + (key >= 'a' && key <= 'z')) { + if (len < sizeof entry_buf) { + entry_buf[len++] = key; + putchar(key); + } + } + } while (key != '\r'); + putchar('\n'); + + if (len == 0) + return VIDEO_CURRENT_MODE; /* Default */ + + v = 0; + for (i = 0; i < len; i++) { + v <<= 4; + key = entry_buf[i] | 0x20; + v += (key > '9') ? key-'a'+10 : key-'0'; + } + + return v; +} + +static void display_menu(void) +{ + struct card_info *card; + struct mode_info *mi; + char ch; + int i; + + puts("Mode: COLSxROWS:\n"); + + ch = '0'; + for (card = video_cards; card < video_cards_end; card++) { + mi = card->modes; + for (i = 0; i < card->nmodes; i++, mi++) { + int visible = mi->x && mi->y; + u16 mode_id = mi->mode ? mi->mode : + (mi->y << 8)+mi->x; + + if (!visible) + continue; /* Hidden mode */ + + printf("%c %04X %3dx%-3d %s\n", + ch, mode_id, mi->x, mi->y, card->card_name); + + if (ch == '9') + ch = 'a'; + else if (ch == 'z' || ch == ' ') + ch = ' '; /* Out of keys... */ + else + ch++; + } + } +} + +#define H(x) ((x)-'a'+10) +#define SCAN ((H('s')<<12)+(H('c')<<8)+(H('a')<<4)+H('n')) + +static unsigned int mode_menu(void) +{ + int key; + unsigned int sel; + + puts("Press to see video modes available, " + " to continue, or wait 30 sec\n"); + + kbd_flush(); + while (1) { + key = getchar_timeout(); + if (key == ' ' || key == 0) + return VIDEO_CURRENT_MODE; /* Default */ + if (key == '\r') + break; + putchar('\a'); /* Beep! */ + } + + + for (;;) { + display_menu(); + + puts("Enter a video mode or \"scan\" to scan for " + "additional modes: "); + sel = get_entry(); + if (sel != SCAN) + return sel; + + probe_cards(1); + } +} + +#ifdef CONFIG_VIDEO_RETAIN +/* Save screen content to the heap */ +struct saved_screen { + int x, y; + int curx, cury; + u16 *data; +} saved; + +static void save_screen(void) +{ + /* Should be called after store_mode_params() */ + saved.x = boot_params.screen_info.orig_video_cols; + saved.y = boot_params.screen_info.orig_video_lines; + saved.curx = boot_params.screen_info.orig_x; + saved.cury = boot_params.screen_info.orig_y; + + if (heap_free() < saved.x*saved.y*sizeof(u16)+512) + return; /* Not enough heap to save the screen */ + + saved.data = GET_HEAP(u16, saved.x*saved.y); + + set_fs(video_segment); + copy_from_fs(saved.data, 0, saved.x*saved.y*sizeof(u16)); +} + +static void restore_screen(void) +{ + /* Should be called after store_mode_params() */ + int xs = boot_params.screen_info.orig_video_cols; + int ys = boot_params.screen_info.orig_video_lines; + int y; + addr_t dst = 0; + u16 *src = saved.data; + u16 ax, bx, dx; + + if (graphic_mode) + return; /* Can't restore onto a graphic mode */ + + if (!src) + return; /* No saved screen contents */ + + /* Restore screen contents */ + + set_fs(video_segment); + for (y = 0; y < ys; y++) { + int npad; + + if (y < saved.y) { + int copy = (xs < saved.x) ? xs : saved.x; + copy_to_fs(dst, src, copy*sizeof(u16)); + dst += copy*sizeof(u16); + src += saved.x; + npad = (xs < saved.x) ? 0 : xs-saved.x; + } else { + npad = xs; + } + + /* Writes "npad" blank characters to + video_segment:dst and advances dst */ + asm volatile("pushw %%es ; " + "movw %2,%%es ; " + "shrw %%cx ; " + "jnc 1f ; " + "stosw \n\t" + "1: rep;stosl ; " + "popw %%es" + : "+D" (dst), "+c" (npad) + : "bdSm" (video_segment), + "a" (0x07200720)); + } + + /* Restore cursor position */ + ax = 0x0200; /* Set cursor position */ + bx = 0; /* Page number (<< 8) */ + dx = (saved.cury << 8)+saved.curx; + asm volatile(INT10 + : "+a" (ax), "+b" (bx), "+d" (dx) + : : "ecx", "esi", "edi"); +} +#else +#define save_screen() ((void)0) +#define restore_screen() ((void)0) +#endif + +void set_video(void) +{ + u16 mode = boot_params.hdr.vid_mode; + + RESET_HEAP(); + + store_mode_params(); + save_screen(); + probe_cards(0); + + for (;;) { + if (mode == ASK_VGA) + mode = mode_menu(); + + if (!set_mode(mode)) + break; + + printf("Undefined video mode number: %x\n", mode); + mode = ASK_VGA; + } + vesa_store_edid(); + store_mode_params(); + + if (do_restore) + restore_screen(); +} --- /dev/null +++ b/arch/i386/boot/video.h @@ -0,0 +1,145 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/video.h + * + * Header file for the real-mode video probing code + */ + +#ifndef BOOT_VIDEO_H +#define BOOT_VIDEO_H + +#include + +/* Enable autodetection of SVGA adapters and modes. */ +#undef CONFIG_VIDEO_SVGA + +/* Enable autodetection of VESA modes */ +#define CONFIG_VIDEO_VESA + +/* Retain screen contents when switching modes */ +#define CONFIG_VIDEO_RETAIN + +/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */ +#undef CONFIG_VIDEO_400_HACK + +/* This code uses an extended set of video mode numbers. These include: + * Aliases for standard modes + * NORMAL_VGA (-1) + * EXTENDED_VGA (-2) + * ASK_VGA (-3) + * Video modes numbered by menu position -- NOT RECOMMENDED because of lack + * of compatibility when extending the table. These are between 0x00 and 0xff. + */ +#define VIDEO_FIRST_MENU 0x0000 + +/* Standard BIOS video modes (BIOS number + 0x0100) */ +#define VIDEO_FIRST_BIOS 0x0100 + +/* VESA BIOS video modes (VESA number + 0x0200) */ +#define VIDEO_FIRST_VESA 0x0200 + +/* Video7 special modes (BIOS number + 0x0900) */ +#define VIDEO_FIRST_V7 0x0900 + +/* Special video modes */ +#define VIDEO_FIRST_SPECIAL 0x0f00 +#define VIDEO_80x25 0x0f00 +#define VIDEO_8POINT 0x0f01 +#define VIDEO_80x43 0x0f02 +#define VIDEO_80x28 0x0f03 +#define VIDEO_CURRENT_MODE 0x0f04 +#define VIDEO_80x30 0x0f05 +#define VIDEO_80x34 0x0f06 +#define VIDEO_80x60 0x0f07 +#define VIDEO_GFX_HACK 0x0f08 +#define VIDEO_LAST_SPECIAL 0x0f09 + +/* Video modes given by resolution */ +#define VIDEO_FIRST_RESOLUTION 0x1000 + +/* The "recalculate timings" flag */ +#define VIDEO_RECALC 0x8000 + +/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ +#ifdef CONFIG_VIDEO_RETAIN +void store_screen(void); +#define DO_STORE() store_screen() +#else +#define DO_STORE() ((void)0) +#endif /* CONFIG_VIDEO_RETAIN */ + +/* + * Mode table structures + */ + +struct mode_info { + u16 mode; /* Mode number (vga= style) */ + u8 x, y; /* Width, height */ +}; + +struct card_info { + const char *card_name; + int (*set_mode)(struct mode_info *mode); + int (*probe)(void); + struct mode_info *modes; + int nmodes; /* Number of probed modes so far */ + int unsafe; /* Probing is unsafe, only do after "scan" */ + u16 xmode_first; /* Unprobed modes to try to call anyway */ + u16 xmode_n; /* Size of unprobed mode range */ +}; + +#define __videocard struct card_info __attribute__((section(".videocards"))) +extern struct card_info video_cards[], video_cards_end[]; + +int mode_defined(u16 mode); /* video.c */ + +/* Basic video information */ +#define ADAPTER_CGA 0 /* CGA/MDA/HGC */ +#define ADAPTER_EGA 1 +#define ADAPTER_VGA 2 + +extern int adapter; +extern u16 video_segment; +extern int force_x, force_y; /* Don't query the BIOS for cols/rows */ +extern int do_restore; /* Restore screen contents */ +extern int graphic_mode; /* Graphics mode with linear frame buffer */ + +/* + * int $0x10 is notorious for touching registers it shouldn't. + * gcc doesn't like %ebp being clobbered, so define it as a push/pop + * sequence here. + */ +#define INT10 "pushl %%ebp; int $0x10; popl %%ebp" + +/* Accessing VGA indexed registers */ +static inline u8 in_idx(u16 port, u8 index) +{ + outb(index, port); + return inb(port+1); +} + +static inline void out_idx(u8 v, u16 port, u8 index) +{ + outw(index+(v << 8), port); +} + +/* Writes a value to an indexed port and then reads the port again */ +static inline u8 tst_idx(u8 v, u16 port, u8 index) +{ + out_idx(port, index, v); + return in_idx(port, index); +} + +/* Get the I/O port of the VGA CRTC */ +u16 vga_crtc(void); /* video-vga.c */ + +#endif /* BOOT_VIDEO_H */ --- /dev/null +++ b/arch/i386/boot/voyager.c @@ -0,0 +1,46 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/voyager.c + * + * Get the Voyager config information + */ + +#include "boot.h" + +#ifdef CONFIG_X86_VOYAGER + +int query_voyager(void) +{ + u8 err; + u16 es, di; + /* Abuse the apm_bios_info area for this */ + u8 *data_ptr = (u8 *)&boot_params.apm_bios_info; + + data_ptr[0] = 0xff; /* Flag on config not found(?) */ + + asm("pushw %%es ; " + "int $0x15 ; " + "setc %0 ; " + "movw %%es, %1 ; " + "popw %%es" + : "=qm" (err), "=rm" (es), "=D" (di) + : "a" (0xffc0)); + + if (err) + return -1; /* Not Voyager */ + + set_fs(es); + copy_from_fs(data_ptr, di, 7); /* Table is 7 bytes apparently */ + return 0; +} + +#endif /* CONFIG_X86_VOYAGER */ --- /dev/null +++ b/arch/i386/kernel/cpu/addon_cpuid_features.c @@ -0,0 +1,50 @@ + +/* + * Routines to indentify additional cpu features that are scattered in + * cpuid space. + */ + +#include + +#include + +struct cpuid_bit { + u16 feature; + u8 reg; + u8 bit; + u32 level; +}; + +enum cpuid_regs { + CR_EAX = 0, + CR_ECX, + CR_EDX, + CR_EBX +}; + +void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c) +{ + u32 max_level; + u32 regs[4]; + const struct cpuid_bit *cb; + + static const struct cpuid_bit cpuid_bits[] = { + { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 }, + { 0, 0, 0, 0 } + }; + + for (cb = cpuid_bits; cb->feature; cb++) { + + /* Verify that the level is valid */ + max_level = cpuid_eax(cb->level & 0xffff0000); + if (max_level < cb->level || + max_level > (cb->level | 0xffff)) + continue; + + cpuid(cb->level, ®s[CR_EAX], ®s[CR_EBX], + ®s[CR_ECX], ®s[CR_EDX]); + + if (regs[cb->reg] & (1 << cb->bit)) + set_bit(cb->feature, c->x86_capability); + } +} --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -353,6 +353,8 @@ if ( xlvl >= 0x80000004 ) get_model_name(c); /* Default name */ } + + init_scattered_cpuid_features(c); } early_intel_workaround(c); --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -29,7 +29,8 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL, - NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", "3dnowext", "3dnow", + NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", + "3dnowext", "3dnow", /* Transmeta-defined */ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, @@ -40,8 +41,9 @@ /* Other (Linux-defined) */ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL, - "constant_tsc", "up", NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "constant_tsc", "up", NULL, "arch_perfmon", + "pebs", "bts", NULL, "sync_rdtsc", + "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ @@ -57,9 +59,16 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* AMD-defined (#2) */ - "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8legacy", "abm", - "sse4a", "misalignsse", - "3dnowprefetch", "osvw", "ibs", NULL, NULL, NULL, NULL, NULL, + "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy", + "altmovcr8", "abm", "sse4a", + "misalignsse", "3dnowprefetch", + "osvw", "ibs", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Auxiliary (Linux-defined) */ + "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; --- a/arch/i386/kernel/e820.c +++ b/arch/i386/kernel/e820.c @@ -734,7 +734,7 @@ case E820_NVS: printk("(ACPI NVS)\n"); break; - default: printk("type %lu\n", e820.map[i].type); + default: printk("type %u\n", e820.map[i].type); break; } } --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -102,19 +102,10 @@ /* * Setup options */ -struct drive_info_struct { char dummy[32]; } drive_info; -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \ - defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) -EXPORT_SYMBOL(drive_info); -#endif struct screen_info screen_info; EXPORT_SYMBOL(screen_info); struct apm_info apm_info; EXPORT_SYMBOL(apm_info); -struct sys_desc_table_struct { - unsigned short length; - unsigned char table[0]; -}; struct edid_info edid_info; EXPORT_SYMBOL_GPL(edid_info); struct ist_info ist_info; @@ -134,7 +125,7 @@ static char __initdata command_line[COMMAND_LINE_SIZE]; -unsigned char __initdata boot_params[PARAM_SIZE]; +struct boot_params __initdata boot_params; #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) struct edd edd; @@ -528,7 +519,6 @@ #endif ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); - drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; edid_info = EDID_INFO; apm_info.bios = APM_BIOS_INFO; --- a/arch/i386/kernel/verify_cpu.S +++ /dev/null @@ -1,94 +0,0 @@ -/* Check if CPU has some minimum CPUID bits - This runs in 16bit mode so that the caller can still use the BIOS - to output errors on the screen */ -#include -#include - -verify_cpu: - pushfl # Save caller passed flags - pushl $0 # Kill any dangerous flags - popfl - -#if CONFIG_X86_MINIMUM_CPU_MODEL >= 4 - pushfl - pop %eax - orl $(1<<18),%eax # try setting AC - push %eax - popfl - pushfl - popl %eax - testl $(1<<18),%eax - jz bad -#endif -#if REQUIRED_MASK1 != 0 - pushfl # standard way to check for cpuid - popl %eax - movl %eax,%ebx - xorl $0x200000,%eax - pushl %eax - popfl - pushfl - popl %eax - cmpl %eax,%ebx - pushfl # standard way to check for cpuid - popl %eax - movl %eax,%ebx - xorl $0x200000,%eax - pushl %eax - popfl - pushfl - popl %eax - cmpl %eax,%ebx - jz bad # REQUIRED_MASK1 != 0 requires CPUID - - movl $0x0,%eax # See if cpuid 1 is implemented - cpuid - cmpl $0x1,%eax - jb bad # no cpuid 1 - -#if REQUIRED_MASK1 & NEED_CMPXCHG64 - /* Some VIA C3s need magic MSRs to enable CX64. Do this here */ - cmpl $0x746e6543,%ebx # Cent - jne 1f - cmpl $0x48727561,%edx # aurH - jne 1f - cmpl $0x736c7561,%ecx # auls - jne 1f - movl $1,%eax # check model - cpuid - movl %eax,%ebx - shr $8,%ebx - andl $0xf,%ebx - cmp $6,%ebx # check family == 6 - jne 1f - shr $4,%eax - andl $0xf,%eax - cmpl $6,%eax # check model >= 6 - jb 1f - # assume models >= 6 all support this MSR - movl $MSR_VIA_FCR,%ecx - rdmsr - orl $((1<<1)|(1<<7)),%eax # enable CMPXCHG64 and PGE - wrmsr -1: -#endif - movl $0x1,%eax # Does the cpu have what it takes - cpuid - -#if CONFIG_X86_MINIMUM_CPU_MODEL > 4 -#error add proper model checking here -#endif - - andl $REQUIRED_MASK1,%edx - xorl $REQUIRED_MASK1,%edx - jnz bad -#endif /* REQUIRED_MASK1 */ - - popfl - xor %eax,%eax - ret - -bad: - popfl - movl $1,%eax - ret --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -427,6 +427,10 @@ This is purely to save memory - each supported CPU requires memory in the static kernel configuration. +config PHYSICAL_ALIGN + hex + default "0x200000" + config HOTPLUG_CPU bool "Support for suspend on SMP and hot-pluggable CPUs (EXPERIMENTAL)" depends on SMP && HOTPLUG && EXPERIMENTAL --- a/arch/x86_64/boot/Makefile +++ b/arch/x86_64/boot/Makefile @@ -1,135 +1,9 @@ # # arch/x86_64/boot/Makefile # -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 1994 by Linus Torvalds -# - -# ROOT_DEV specifies the default root-device when making the image. -# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case -# the default of FLOPPY is used by 'build'. - -ROOT_DEV := CURRENT - -# If you want to preset the SVGA mode, uncomment the next line and -# set SVGA_MODE to whatever number you want. -# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. -# The number is the same as you would ordinarily press at bootup. - -SVGA_MODE := -DSVGA_MODE=NORMAL_VGA - -# If you want the RAM disk device, define this to be the size in blocks. - -#RAMDISK := -DRAMDISK=512 - -targets := vmlinux.bin bootsect bootsect.o \ - setup setup.o bzImage mtools.conf - -EXTRA_CFLAGS := -m32 - -hostprogs-y := tools/build -HOST_EXTRACFLAGS += $(LINUXINCLUDE) -subdir- := compressed/ #Let make clean descend in compressed/ -# --------------------------------------------------------------------------- - -$(obj)/bzImage: IMAGE_OFFSET := 0x100000 -$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ -$(obj)/bzImage: BUILDFLAGS := -b - -quiet_cmd_image = BUILD $@ -cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ - $(obj)/vmlinux.bin $(ROOT_DEV) > $@ - -$(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ - $(obj)/vmlinux.bin $(obj)/tools/build FORCE - $(call if_changed,image) - @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' - -$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE - $(call if_changed,objcopy) - -LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary -LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext - -$(obj)/setup $(obj)/bootsect: %: %.o FORCE - $(call if_changed,ld) - -$(obj)/compressed/vmlinux: FORCE - $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@ - -# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel -FDARGS = -# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel -FDINITRD = - -image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,) - -$(obj)/mtools.conf: $(src)/mtools.conf.in - sed -e 's|@OBJ@|$(obj)|g' < $< > $@ - -# This requires write access to /dev/fd0 -zdisk: $(BOOTIMAGE) $(obj)/mtools.conf - MTOOLSRC=$(obj)/mtools.conf mformat a: ; sync - syslinux /dev/fd0 ; sync - echo '$(image_cmdline)' | \ - MTOOLSRC=$(obj)/mtools.conf mcopy - a:syslinux.cfg - if [ -f '$(FDINITRD)' ] ; then \ - MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' a:initrd.img ; \ - fi - MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux ; sync - -# These require being root or having syslinux 2.02 or higher installed -fdimage fdimage144: $(BOOTIMAGE) $(obj)/mtools.conf - dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440 - MTOOLSRC=$(obj)/mtools.conf mformat v: ; sync - syslinux $(obj)/fdimage ; sync - echo '$(image_cmdline)' | \ - MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg - if [ -f '$(FDINITRD)' ] ; then \ - MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' v:initrd.img ; \ - fi - MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux ; sync - -fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf - dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880 - MTOOLSRC=$(obj)/mtools.conf mformat w: ; sync - syslinux $(obj)/fdimage ; sync - echo '$(image_cmdline)' | \ - MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg - if [ -f '$(FDINITRD)' ] ; then \ - MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' w:initrd.img ; \ - fi - MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux ; sync - -isoimage: $(BOOTIMAGE) - -rm -rf $(obj)/isoimage - mkdir $(obj)/isoimage - for i in lib lib64 share end ; do \ - if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \ - cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \ - break ; \ - fi ; \ - if [ $$i = end ] ; then exit 1 ; fi ; \ - done - cp $(BOOTIMAGE) $(obj)/isoimage/linux - echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg - if [ -f '$(FDINITRD)' ] ; then \ - cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \ - fi - mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \ - -no-emul-boot -boot-load-size 4 -boot-info-table \ - $(obj)/isoimage - rm -rf $(obj)/isoimage - -zlilo: $(BOOTIMAGE) - if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi - if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi - cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz - cp System.map $(INSTALL_PATH)/ - if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi +# The actual boot code is shared with i386 including the Makefile. +# So tell kbuild that we fetch the code from i386 and include the +# Makefile from i386 too. -install: - sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" +src := arch/i386/boot +include $(src)/Makefile --- a/arch/x86_64/boot/bootsect.S +++ /dev/null @@ -1,98 +0,0 @@ -/* - * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds - * - * modified by Drew Eckhardt - * modified by Bruce Evans (bde) - * modified by Chris Noe (May 1999) (as86 -> gas) - * gutted by H. Peter Anvin (Jan 2003) - * - * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment - * addresses must be multiplied by 16 to obtain their respective linear - * addresses. To avoid confusion, linear addresses are written using leading - * hex while segment addresses are written as segment:offset. - * - */ - -#include - -SETUPSECTS = 4 /* default nr of setup-sectors */ -BOOTSEG = 0x07C0 /* original address of boot-sector */ -INITSEG = DEF_INITSEG /* we move boot here - out of the way */ -SETUPSEG = DEF_SETUPSEG /* setup starts here */ -SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */ -SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */ - /* to be loaded */ -ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */ -SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */ - -#ifndef SVGA_MODE -#define SVGA_MODE ASK_VGA -#endif - -#ifndef RAMDISK -#define RAMDISK 0 -#endif - -#ifndef ROOT_RDONLY -#define ROOT_RDONLY 1 -#endif - -.code16 -.text - -.global _start -_start: - - # Normalize the start address - jmpl $BOOTSEG, $start2 - -start2: - movw %cs, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw $0x7c00, %sp - sti - cld - - movw $bugger_off_msg, %si - -msg_loop: - lodsb - andb %al, %al - jz die - movb $0xe, %ah - movw $7, %bx - int $0x10 - jmp msg_loop - -die: - # Allow the user to press a key, then reboot - xorw %ax, %ax - int $0x16 - int $0x19 - - # int 0x19 should never return. In case it does anyway, - # invoke the BIOS reset code... - ljmp $0xf000,$0xfff0 - - -bugger_off_msg: - .ascii "Direct booting from floppy is no longer supported.\r\n" - .ascii "Please use a boot loader program instead.\r\n" - .ascii "\n" - .ascii "Remove disk and press any key to reboot . . .\r\n" - .byte 0 - - - # Kernel attributes; used by setup - - .org 497 -setup_sects: .byte SETUPSECTS -root_flags: .word ROOT_RDONLY -syssize: .word SYSSIZE -swap_dev: .word SWAP_DEV -ram_size: .word RAMDISK -vid_mode: .word SVGA_MODE -root_dev: .word ROOT_DEV -boot_flag: .word 0xAA55 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile @@ -7,11 +7,12 @@ # targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o -EXTRA_AFLAGS := -traditional -# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with -# -m32 -CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin +CFLAGS := -m64 -D__KERNEL__ $(LINUXINCLUDE) -O2 \ + -fno-strict-aliasing -fPIC -mcmodel=small \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-stack-protector) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ LDFLAGS := -m elf_x86_64 LDFLAGS_vmlinux := -T --- a/arch/x86_64/boot/compressed/head.S +++ b/arch/x86_64/boot/compressed/head.S @@ -46,10 +46,10 @@ * at and where we were actually loaded at. This can only be done * with a short local call on x86. Nothing else will tell us what * address we are running at. The reserved chunk of the real-mode - * data at 0x34-0x3f are used as the stack for this calculation. - * Only 4 bytes are needed. + * data at 0x1e4 (defined as a scratch field) are used as the stack + * for this calculation. Only 4 bytes are needed. */ - leal 0x40(%esi), %esp + leal (0x1e4+4)(%esi), %esp call 1f 1: popl %ebp subl $1b, %ebp --- a/arch/x86_64/boot/install.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -. $srctree/arch/i386/boot/install.sh --- a/arch/x86_64/boot/mtools.conf.in +++ /dev/null @@ -1,17 +0,0 @@ -# -# mtools configuration file for "make (b)zdisk" -# - -# Actual floppy drive -drive a: - file="/dev/fd0" - -# 1.44 MB floppy disk image -drive v: - file="@OBJ@/fdimage" cylinders=80 heads=2 sectors=18 filter - -# 2.88 MB floppy disk image (mostly for virtual uses) -drive w: - file="@OBJ@/fdimage" cylinders=80 heads=2 sectors=36 filter - - --- a/arch/x86_64/boot/setup.S +++ /dev/null @@ -1,826 +0,0 @@ -/* - * setup.S Copyright (C) 1991, 1992 Linus Torvalds - * - * setup.s is responsible for getting the system data from the BIOS, - * and putting them into the appropriate places in system memory. - * both setup.s and system has been loaded by the bootblock. - * - * This code asks the bios for memory/disk/other parameters, and - * puts them in a "safe" place: 0x90000-0x901FF, ie where the - * boot-block used to be. It is then up to the protected mode - * system to read them from there before the area is overwritten - * for buffer-blocks. - * - * Move PS/2 aux init code to psaux.c - * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 - * - * some changes and additional features by Christoph Niemann, - * March 1993/June 1994 (Christoph.Niemann@linux.org) - * - * add APM BIOS checking by Stephen Rothwell, May 1994 - * (sfr@canb.auug.org.au) - * - * High load stuff, initrd support and position independency - * by Hans Lermen & Werner Almesberger, February 1996 - * , - * - * Video handling moved to video.S by Martin Mares, March 1996 - * - * - * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david - * parsons) to avoid loadlin confusion, July 1997 - * - * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. - * - * - * Fix to work around buggy BIOSes which don't use carry bit correctly - * and/or report extended memory in CX/DX for e801h memory size detection - * call. As a result the kernel got wrong figures. The int15/e801h docs - * from Ralf Brown interrupt list seem to indicate AX/BX should be used - * anyway. So to avoid breaking many machines (presumably there was a reason - * to orginally use CX/DX instead of AX/BX), we do a kludge to see - * if CX/DX have been changed in the e801 call and if so use AX/BX . - * Michael Miller, April 2001 - * - * Added long mode checking and SSE force. March 2003, Andi Kleen. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* Signature words to ensure LILO loaded us right */ -#define SIG1 0xAA55 -#define SIG2 0x5A5A - -INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way -SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). -SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment - # ... and the former contents of CS - -DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020 - -.code16 -.globl begtext, begdata, begbss, endtext, enddata, endbss - -.text -begtext: -.data -begdata: -.bss -begbss: -.text - -start: - jmp trampoline - -# This is the setup header, and it must start at %cs:2 (old 0x9020:2) - - .ascii "HdrS" # header signature - .word 0x0206 # header version number (>= 0x0105) - # or else old loadlin-1.5 will fail) -realmode_swtch: .word 0, 0 # default_switch, SETUPSEG -start_sys_seg: .word SYSSEG - .word kernel_version # pointing to kernel version string - # above section of header is compatible - # with loadlin-1.5 (header v1.5). Don't - # change it. - -type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, - # Bootlin, SYSLX, bootsect...) - # See Documentation/i386/boot.txt for - # assigned ids - -# flags, unused bits must be zero (RFU) bit within loadflags -loadflags: -LOADED_HIGH = 1 # If set, the kernel is loaded high -CAN_USE_HEAP = 0x80 # If set, the loader also has set - # heap_end_ptr to tell how much - # space behind setup.S can be used for - # heap purposes. - # Only the loader knows what is free -#ifndef __BIG_KERNEL__ - .byte 0 -#else - .byte LOADED_HIGH -#endif - -setup_move_size: .word 0x8000 # size to move, when setup is not - # loaded at 0x90000. We will move setup - # to 0x90000 then just before jumping - # into the kernel. However, only the - # loader knows how much data behind - # us also needs to be loaded. - -code32_start: # here loaders can put a different - # start address for 32-bit code. -#ifndef __BIG_KERNEL__ - .long 0x1000 # 0x1000 = default for zImage -#else - .long 0x100000 # 0x100000 = default for big kernel -#endif - -ramdisk_image: .long 0 # address of loaded ramdisk image - # Here the loader puts the 32-bit - # address where it loaded the image. - # This only will be read by the kernel. - -ramdisk_size: .long 0 # its size in bytes - -bootsect_kludge: - .long 0 # obsolete - -heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later) - # space from here (exclusive) down to - # end of setup code can be used by setup - # for local heap purposes. - -pad1: .word 0 -cmd_line_ptr: .long 0 # (Header version 0x0202 or later) - # If nonzero, a 32-bit pointer - # to the kernel command line. - # The command line should be - # located between the start of - # setup and the end of low - # memory (0xa0000), or it may - # get overwritten before it - # gets read. If this field is - # used, there is no longer - # anything magical about the - # 0x90000 segment; the setup - # can be located anywhere in - # low memory 0x10000 or higher. - -ramdisk_max: .long 0xffffffff -kernel_alignment: .long 0x200000 # physical addr alignment required for - # protected mode relocatable kernel -#ifdef CONFIG_RELOCATABLE -relocatable_kernel: .byte 1 -#else -relocatable_kernel: .byte 0 -#endif -pad2: .byte 0 -pad3: .word 0 - -cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, - #added with boot protocol - #version 2.06 - -trampoline: call start_of_setup - .align 16 - # The offset at this point is 0x240 - .space (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff) -# End of setup header ##################################################### - -start_of_setup: -# Bootlin depends on this being done early - movw $0x01500, %ax - movb $0x81, %dl - int $0x13 - -#ifdef SAFE_RESET_DISK_CONTROLLER -# Reset the disk controller. - movw $0x0000, %ax - movb $0x80, %dl - int $0x13 -#endif - -# Set %ds = %cs, we know that SETUPSEG = %cs at this point - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds -# Check signature at end of setup - cmpw $SIG1, setup_sig1 - jne bad_sig - - cmpw $SIG2, setup_sig2 - jne bad_sig - - jmp good_sig1 - -# Routine to print asciiz string at ds:si -prtstr: - lodsb - andb %al, %al - jz fin - - call prtchr - jmp prtstr - -fin: ret - -# Space printing -prtsp2: call prtspc # Print double space -prtspc: movb $0x20, %al # Print single space (note: fall-thru) - -prtchr: - pushw %ax - pushw %cx - movw $0007,%bx - movw $0x01, %cx - movb $0x0e, %ah - int $0x10 - popw %cx - popw %ax - ret - -beep: movb $0x07, %al - jmp prtchr - -no_sig_mess: .string "No setup signature found ..." - -good_sig1: - jmp good_sig - -# We now have to find the rest of the setup code/data -bad_sig: - movw %cs, %ax # SETUPSEG - subw $DELTA_INITSEG, %ax # INITSEG - movw %ax, %ds - xorb %bh, %bh - movb (497), %bl # get setup sect from bootsect - subw $4, %bx # LILO loads 4 sectors of setup - shlw $8, %bx # convert to words (1sect=2^8 words) - movw %bx, %cx - shrw $3, %bx # convert to segment - addw $SYSSEG, %bx - movw %bx, %cs:start_sys_seg -# Move rest of setup code/data to here - movw $2048, %di # four sectors loaded by LILO - subw %si, %si - movw %cs, %ax # aka SETUPSEG - movw %ax, %es - movw $SYSSEG, %ax - movw %ax, %ds - rep - movsw - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds - cmpw $SIG1, setup_sig1 - jne no_sig - - cmpw $SIG2, setup_sig2 - jne no_sig - - jmp good_sig - -no_sig: - lea no_sig_mess, %si - call prtstr - -no_sig_loop: - jmp no_sig_loop - -good_sig: - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %ds -# Check if an old loader tries to load a big-kernel - testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel? - jz loader_ok # No, no danger for old loaders. - - cmpb $0, %cs:type_of_loader # Do we have a loader that - # can deal with us? - jnz loader_ok # Yes, continue. - - pushw %cs # No, we have an old loader, - popw %ds # die. - lea loader_panic_mess, %si - call prtstr - - jmp no_sig_loop - -loader_panic_mess: .string "Wrong loader, giving up..." - -loader_ok: - /* check for long mode. */ - /* we have to do this before the VESA setup, otherwise the user - can't see the error message. */ - - pushw %ds - movw %cs,%ax - movw %ax,%ds - - call verify_cpu - testl %eax,%eax - jz sse_ok - -no_longmode: - call beep - lea long_mode_panic,%si - call prtstr -no_longmode_loop: - jmp no_longmode_loop -long_mode_panic: - .string "Your CPU does not support long mode. Use a 32bit distribution." - .byte 0 - -#include "../kernel/verify_cpu.S" -sse_ok: - popw %ds - -# tell BIOS we want to go to long mode - movl $0xec00,%eax # declare target operating mode - movl $2,%ebx # long mode - int $0x15 - -# Get memory size (extended mem, kB) - - xorl %eax, %eax - movl %eax, (0x1e0) -#ifndef STANDARD_MEMORY_BIOS_CALL - movb %al, (E820NR) -# Try three different memory detection schemes. First, try -# e820h, which lets us assemble a memory map, then try e801h, -# which returns a 32-bit memory size, and finally 88h, which -# returns 0-64m - -# method E820H: -# the memory map from hell. e820h returns memory classified into -# a whole bunch of different types, and allows memory holes and -# everything. We scan through this memory map and build a list -# of the first 32 memory areas, which we return at [E820MAP]. -# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification. - -#define SMAP 0x534d4150 - -meme820: - xorl %ebx, %ebx # continuation counter - movw $E820MAP, %di # point into the whitelist - # so we can have the bios - # directly write into it. - -jmpe820: - movl $0x0000e820, %eax # e820, upper word zeroed - movl $SMAP, %edx # ascii 'SMAP' - movl $20, %ecx # size of the e820rec - pushw %ds # data record. - popw %es - int $0x15 # make the call - jc bail820 # fall to e801 if it fails - - cmpl $SMAP, %eax # check the return is `SMAP' - jne bail820 # fall to e801 if it fails - -# cmpl $1, 16(%di) # is this usable memory? -# jne again820 - - # If this is usable memory, we save it by simply advancing %di by - # sizeof(e820rec). - # -good820: - movb (E820NR), %al # up to 128 entries - cmpb $E820MAX, %al - jae bail820 - - incb (E820NR) - movw %di, %ax - addw $20, %ax - movw %ax, %di -again820: - cmpl $0, %ebx # check to see if - jne jmpe820 # %ebx is set to EOF -bail820: - - -# method E801H: -# memory size is in 1k chunksizes, to avoid confusing loadlin. -# we store the 0xe801 memory size in a completely different place, -# because it will most likely be longer than 16 bits. -# (use 1e0 because that's what Larry Augustine uses in his -# alternative new memory detection scheme, and it's sensible -# to write everything into the same place.) - -meme801: - stc # fix to work around buggy - xorw %cx,%cx # BIOSes which don't clear/set - xorw %dx,%dx # carry on pass/error of - # e801h memory size call - # or merely pass cx,dx though - # without changing them. - movw $0xe801, %ax - int $0x15 - jc mem88 - - cmpw $0x0, %cx # Kludge to handle BIOSes - jne e801usecxdx # which report their extended - cmpw $0x0, %dx # memory in AX/BX rather than - jne e801usecxdx # CX/DX. The spec I have read - movw %ax, %cx # seems to indicate AX/BX - movw %bx, %dx # are more reasonable anyway... - -e801usecxdx: - andl $0xffff, %edx # clear sign extend - shll $6, %edx # and go from 64k to 1k chunks - movl %edx, (0x1e0) # store extended memory size - andl $0xffff, %ecx # clear sign extend - addl %ecx, (0x1e0) # and add lower memory into - # total size. - -# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or -# 64mb, depending on the bios) in ax. -mem88: - -#endif - movb $0x88, %ah - int $0x15 - movw %ax, (2) - -# Set the keyboard repeat rate to the max - movw $0x0305, %ax - xorw %bx, %bx - int $0x16 - -# Check for video adapter and its parameters and allow the -# user to browse video modes. - call video # NOTE: we need %ds pointing - # to bootsector - -# Get hd0 data... - xorw %ax, %ax - movw %ax, %ds - ldsw (4 * 0x41), %si - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - pushw %ax - movw %ax, %es - movw $0x0080, %di - movw $0x10, %cx - pushw %cx - cld - rep - movsb -# Get hd1 data... - xorw %ax, %ax - movw %ax, %ds - ldsw (4 * 0x46), %si - popw %cx - popw %es - movw $0x0090, %di - rep - movsb -# Check that there IS a hd1 :-) - movw $0x01500, %ax - movb $0x81, %dl - int $0x13 - jc no_disk1 - - cmpb $3, %ah - je is_disk1 - -no_disk1: - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %es - movw $0x0090, %di - movw $0x10, %cx - xorw %ax, %ax - cld - rep - stosb -is_disk1: - -# Check for PS/2 pointing device - movw %cs, %ax # aka SETUPSEG - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ax, %ds - movb $0, (0x1ff) # default is no pointing device - int $0x11 # int 0x11: equipment list - testb $0x04, %al # check if mouse installed - jz no_psmouse - - movb $0xAA, (0x1ff) # device present -no_psmouse: - -#include "../../i386/boot/edd.S" - -# Now we want to move to protected mode ... - cmpw $0, %cs:realmode_swtch - jz rmodeswtch_normal - - lcall *%cs:realmode_swtch - - jmp rmodeswtch_end - -rmodeswtch_normal: - pushw %cs - call default_switch - -rmodeswtch_end: -# we get the code32 start address and modify the below 'jmpi' -# (loader may have changed it) - movl %cs:code32_start, %eax - movl %eax, %cs:code32 - -# Now we move the system to its rightful place ... but we check if we have a -# big-kernel. In that case we *must* not move it ... - testb $LOADED_HIGH, %cs:loadflags - jz do_move0 # .. then we have a normal low - # loaded zImage - # .. or else we have a high - # loaded bzImage - jmp end_move # ... and we skip moving - -do_move0: - movw $0x100, %ax # start of destination segment - movw %cs, %bp # aka SETUPSEG - subw $DELTA_INITSEG, %bp # aka INITSEG - movw %cs:start_sys_seg, %bx # start of source segment - cld -do_move: - movw %ax, %es # destination segment - incb %ah # instead of add ax,#0x100 - movw %bx, %ds # source segment - addw $0x100, %bx - subw %di, %di - subw %si, %si - movw $0x800, %cx - rep - movsw - cmpw %bp, %bx # assume start_sys_seg > 0x200, - # so we will perhaps read one - # page more than needed, but - # never overwrite INITSEG - # because destination is a - # minimum one page below source - jb do_move - -end_move: -# then we load the segment descriptors - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds - -# Check whether we need to be downward compatible with version <=201 - cmpl $0, cmd_line_ptr - jne end_move_self # loader uses version >=202 features - cmpb $0x20, type_of_loader - je end_move_self # bootsect loader, we know of it - -# Boot loader doesnt support boot protocol version 2.02. -# If we have our code not at 0x90000, we need to move it there now. -# We also then need to move the params behind it (commandline) -# Because we would overwrite the code on the current IP, we move -# it in two steps, jumping high after the first one. - movw %cs, %ax - cmpw $SETUPSEG, %ax - je end_move_self - - cli # make sure we really have - # interrupts disabled ! - # because after this the stack - # should not be used - subw $DELTA_INITSEG, %ax # aka INITSEG - movw %ss, %dx - cmpw %ax, %dx - jb move_self_1 - - addw $INITSEG, %dx - subw %ax, %dx # this will go into %ss after - # the move -move_self_1: - movw %ax, %ds - movw $INITSEG, %ax # real INITSEG - movw %ax, %es - movw %cs:setup_move_size, %cx - std # we have to move up, so we use - # direction down because the - # areas may overlap - movw %cx, %di - decw %di - movw %di, %si - subw $move_self_here+0x200, %cx - rep - movsb - ljmp $SETUPSEG, $move_self_here - -move_self_here: - movw $move_self_here+0x200, %cx - rep - movsb - movw $SETUPSEG, %ax - movw %ax, %ds - movw %dx, %ss -end_move_self: # now we are at the right place - lidt idt_48 # load idt with 0,0 - xorl %eax, %eax # Compute gdt_base - movw %ds, %ax # (Convert %ds:gdt to a linear ptr) - shll $4, %eax - addl $gdt, %eax - movl %eax, (gdt_48+2) - lgdt gdt_48 # load gdt with whatever is - # appropriate - -# that was painless, now we enable a20 - call empty_8042 - - movb $0xD1, %al # command write - outb %al, $0x64 - call empty_8042 - - movb $0xDF, %al # A20 on - outb %al, $0x60 - call empty_8042 - -# -# You must preserve the other bits here. Otherwise embarrasing things -# like laptops powering off on boot happen. Corrected version by Kira -# Brown from Linux 2.2 -# - inb $0x92, %al # - orb $02, %al # "fast A20" version - outb %al, $0x92 # some chips have only this - -# wait until a20 really *is* enabled; it can take a fair amount of -# time on certain systems; Toshiba Tecras are known to have this -# problem. The memory location used here (0x200) is the int 0x80 -# vector, which should be safe to use. - - xorw %ax, %ax # segment 0x0000 - movw %ax, %fs - decw %ax # segment 0xffff (HMA) - movw %ax, %gs -a20_wait: - incw %ax # unused memory location <0xfff0 - movw %ax, %fs:(0x200) # we use the "int 0x80" vector - cmpw %gs:(0x210), %ax # and its corresponding HMA addr - je a20_wait # loop until no longer aliased - -# make sure any possible coprocessor is properly reset.. - xorw %ax, %ax - outb %al, $0xf0 - call delay - - outb %al, $0xf1 - call delay - -# well, that went ok, I hope. Now we mask all interrupts - the rest -# is done in init_IRQ(). - movb $0xFF, %al # mask all interrupts for now - outb %al, $0xA1 - call delay - - movb $0xFB, %al # mask all irq's but irq2 which - outb %al, $0x21 # is cascaded - -# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't -# need no steenking BIOS anyway (except for the initial loading :-). -# The BIOS-routine wants lots of unnecessary data, and it's less -# "interesting" anyway. This is how REAL programmers do it. -# -# Well, now's the time to actually move into protected mode. To make -# things as simple as possible, we do no register set-up or anything, -# we let the gnu-compiled 32-bit programs do that. We just jump to -# absolute address 0x1000 (or the loader supplied one), -# in 32-bit protected mode. -# -# Note that the short jump isn't strictly needed, although there are -# reasons why it might be a good idea. It won't hurt in any case. - movw $1, %ax # protected mode (PE) bit - lmsw %ax # This is it! - jmp flush_instr - -flush_instr: - xorw %bx, %bx # Flag to indicate a boot - xorl %esi, %esi # Pointer to real-mode code - movw %cs, %si - subw $DELTA_INITSEG, %si - shll $4, %esi # Convert to 32-bit pointer -# NOTE: For high loaded big kernels we need a -# jmpi 0x100000,__KERNEL_CS -# -# but we yet haven't reloaded the CS register, so the default size -# of the target offset still is 16 bit. -# However, using an operand prefix (0x66), the CPU will properly -# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference -# Manual, Mixing 16-bit and 32-bit code, page 16-6) - - .byte 0x66, 0xea # prefix + jmpi-opcode -code32: .long 0x1000 # will be set to 0x100000 - # for big kernels - .word __KERNEL_CS - -# Here's a bunch of information about your current kernel.. -kernel_version: .ascii UTS_RELEASE - .ascii " (" - .ascii LINUX_COMPILE_BY - .ascii "@" - .ascii LINUX_COMPILE_HOST - .ascii ") " - .ascii UTS_VERSION - .byte 0 - -# This is the default real mode switch routine. -# to be called just before protected mode transition -default_switch: - cli # no interrupts allowed ! - movb $0x80, %al # disable NMI for bootup - # sequence - outb %al, $0x70 - lret - - -# This routine checks that the keyboard command queue is empty -# (after emptying the output buffers) -# -# Some machines have delusions that the keyboard buffer is always full -# with no keyboard attached... -# -# If there is no keyboard controller, we will usually get 0xff -# to all the reads. With each IO taking a microsecond and -# a timeout of 100,000 iterations, this can take about half a -# second ("delay" == outb to port 0x80). That should be ok, -# and should also be plenty of time for a real keyboard controller -# to empty. -# - -empty_8042: - pushl %ecx - movl $100000, %ecx - -empty_8042_loop: - decl %ecx - jz empty_8042_end_loop - - call delay - - inb $0x64, %al # 8042 status port - testb $1, %al # output buffer? - jz no_output - - call delay - inb $0x60, %al # read it - jmp empty_8042_loop - -no_output: - testb $2, %al # is input buffer full? - jnz empty_8042_loop # yes - loop -empty_8042_end_loop: - popl %ecx - ret - -# Read the cmos clock. Return the seconds in al -gettime: - pushw %cx - movb $0x02, %ah - int $0x1a - movb %dh, %al # %dh contains the seconds - andb $0x0f, %al - movb %dh, %ah - movb $0x04, %cl - shrb %cl, %ah - aad - popw %cx - ret - -# Delay is needed after doing I/O -delay: - outb %al,$0x80 - ret - -# Descriptor tables -gdt: - .word 0, 0, 0, 0 # dummy - - .word 0, 0, 0, 0 # unused - - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) - .word 0 # base address = 0 - .word 0x9A00 # code read/exec - .word 0x00CF # granularity = 4096, 386 - # (+5th nibble of limit) - - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) - .word 0 # base address = 0 - .word 0x9200 # data read/write - .word 0x00CF # granularity = 4096, 386 - # (+5th nibble of limit) -gdt_end: -idt_48: - .word 0 # idt limit = 0 - .word 0, 0 # idt base = 0L -gdt_48: - .word gdt_end-gdt-1 # gdt limit - .word 0, 0 # gdt base (filled in later) - -# Include video setup & detection code - -#include "../../i386/boot/video.S" - -# Setup signature -- must be last -setup_sig1: .word SIG1 -setup_sig2: .word SIG2 - -# After this point, there is some free space which is used by the video mode -# handling code to store the temporary mode table (not used by the kernel). - -modelist: - -.text -endtext: -.data -enddata: -.bss -endbss: --- a/arch/x86_64/boot/tools/build.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1997 Martin Mares - */ - -/* - * This file builds a disk-image from three different files: - * - * - bootsect: compatibility mbr which prints an error message if - * someone tries to boot the kernel directly. - * - setup: 8086 machine code, sets up system parm - * - system: 80386 code for actual system - * - * It does some checking that all files are of the correct type, and - * just writes the result to stdout, removing headers and padding to - * the right amount. It also writes some system data to stderr. - */ - -/* - * Changes by tytso to allow root device specification - * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 - * Cross compiling fixes by Gertjan van Wingerde, July 1996 - * Rewritten by Martin Mares, April 1997 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef unsigned char byte; -typedef unsigned short word; -typedef unsigned long u32; - -#define DEFAULT_MAJOR_ROOT 0 -#define DEFAULT_MINOR_ROOT 0 - -/* Minimal number of setup sectors (see also bootsect.S) */ -#define SETUP_SECTS 4 - -byte buf[1024]; -int fd; -int is_big_kernel; - -void die(const char * str, ...) -{ - va_list args; - va_start(args, str); - vfprintf(stderr, str, args); - fputc('\n', stderr); - exit(1); -} - -void file_open(const char *name) -{ - if ((fd = open(name, O_RDONLY, 0)) < 0) - die("Unable to open `%s': %m", name); -} - -void usage(void) -{ - die("Usage: build [-b] bootsect setup system [rootdev] [> image]"); -} - -int main(int argc, char ** argv) -{ - unsigned int i, c, sz, setup_sectors; - u32 sys_size; - byte major_root, minor_root; - struct stat sb; - - if (argc > 2 && !strcmp(argv[1], "-b")) - { - is_big_kernel = 1; - argc--, argv++; - } - if ((argc < 4) || (argc > 5)) - usage(); - if (argc > 4) { - if (!strcmp(argv[4], "CURRENT")) { - if (stat("/", &sb)) { - perror("/"); - die("Couldn't stat /"); - } - major_root = major(sb.st_dev); - minor_root = minor(sb.st_dev); - } else if (strcmp(argv[4], "FLOPPY")) { - if (stat(argv[4], &sb)) { - perror(argv[4]); - die("Couldn't stat root device."); - } - major_root = major(sb.st_rdev); - minor_root = minor(sb.st_rdev); - } else { - major_root = 0; - minor_root = 0; - } - } else { - major_root = DEFAULT_MAJOR_ROOT; - minor_root = DEFAULT_MINOR_ROOT; - } - fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); - - file_open(argv[1]); - i = read(fd, buf, sizeof(buf)); - fprintf(stderr,"Boot sector %d bytes.\n",i); - if (i != 512) - die("Boot block must be exactly 512 bytes"); - if (buf[510] != 0x55 || buf[511] != 0xaa) - die("Boot block hasn't got boot flag (0xAA55)"); - buf[508] = minor_root; - buf[509] = major_root; - if (write(1, buf, 512) != 512) - die("Write call failed"); - close (fd); - - file_open(argv[2]); /* Copy the setup code */ - for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c ) - if (write(1, buf, c) != c) - die("Write call failed"); - if (c != 0) - die("read-error on `setup'"); - close (fd); - - setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */ - /* for compatibility with ancient versions of LILO. */ - if (setup_sectors < SETUP_SECTS) - setup_sectors = SETUP_SECTS; - fprintf(stderr, "Setup is %d bytes.\n", i); - memset(buf, 0, sizeof(buf)); - while (i < setup_sectors * 512) { - c = setup_sectors * 512 - i; - if (c > sizeof(buf)) - c = sizeof(buf); - if (write(1, buf, c) != c) - die("Write call failed"); - i += c; - } - - file_open(argv[3]); - if (fstat (fd, &sb)) - die("Unable to stat `%s': %m", argv[3]); - sz = sb.st_size; - fprintf (stderr, "System is %d kB\n", sz/1024); - sys_size = (sz + 15) / 16; - if (!is_big_kernel && sys_size > DEF_SYSSIZE) - die("System is too big. Try using bzImage or modules."); - while (sz > 0) { - int l, n; - - l = (sz > sizeof(buf)) ? sizeof(buf) : sz; - if ((n=read(fd, buf, l)) != l) { - if (n < 0) - die("Error reading %s: %m", argv[3]); - else - die("%s: Unexpected EOF", argv[3]); - } - if (write(1, buf, l) != l) - die("Write failed"); - sz -= l; - } - close(fd); - - if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */ - die("Output: seek failed"); - buf[0] = setup_sectors; - if (write(1, buf, 1) != 1) - die("Write of setup sector count failed"); - if (lseek(1, 500, SEEK_SET) != 500) - die("Output: seek failed"); - buf[0] = (sys_size & 0xff); - buf[1] = ((sys_size >> 8) & 0xff); - buf[2] = ((sys_size >> 16) & 0xff); - buf[3] = ((sys_size >> 24) & 0xff); - if (write(1, buf, 4) != 4) - die("Write of image length failed"); - - return 0; /* Everything is OK */ -} --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -43,6 +43,7 @@ obj-y += topology.o obj-y += intel_cacheinfo.o +obj-y += addon_cpuid_features.o obj-y += pcspeaker.o CFLAGS_vsyscall.o := $(PROFILING) -g0 @@ -53,6 +54,7 @@ topology-y += ../../i386/kernel/topology.o microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o +addon_cpuid_features-y += ../../i386/kernel/cpu/addon_cpuid_features.o quirks-y += ../../i386/kernel/quirks.o i8237-y += ../../i386/kernel/i8237.o msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -846,6 +846,8 @@ c->x86_capability[2] = cpuid_edx(0x80860001); } + init_scattered_cpuid_features(c); + c->apicid = phys_pkg_id(0); /* @@ -931,7 +933,7 @@ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, + "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe", /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -947,10 +949,11 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Other (Linux-defined) */ - "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL, - "constant_tsc", NULL, NULL, - "up", NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", + NULL, NULL, NULL, NULL, + "constant_tsc", "up", NULL, "arch_perfmon", + "pebs", "bts", NULL, "sync_rdtsc", + "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ @@ -961,7 +964,7 @@ /* VIA/Cyrix/Centaur-defined */ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -972,6 +975,12 @@ "osvw", "ibs", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Auxiliary (Linux-defined) */ + "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; static char *x86_power_flags[] = { "ts", /* temperature sensor */ --- a/arch/x86_64/kernel/verify_cpu.S +++ b/arch/x86_64/kernel/verify_cpu.S @@ -37,20 +37,6 @@ pushl $0 # Kill any dangerous flags popfl - /* minimum CPUID flags for x86-64 as defined by AMD */ -#define M(x) (1<<(x)) -#define M2(a,b) M(a)|M(b) -#define M4(a,b,c,d) M(a)|M(b)|M(c)|M(d) - -#define SSE_MASK \ - (M2(X86_FEATURE_XMM,X86_FEATURE_XMM2)) -#define REQUIRED_MASK1 \ - (M4(X86_FEATURE_FPU,X86_FEATURE_PSE,X86_FEATURE_TSC,X86_FEATURE_MSR)|\ - M4(X86_FEATURE_PAE,X86_FEATURE_CX8,X86_FEATURE_PGE,X86_FEATURE_CMOV)|\ - M(X86_FEATURE_FXSR)) -#define REQUIRED_MASK2 \ - (M(X86_FEATURE_LM - 32)) - pushfl # standard way to check for cpuid popl %eax movl %eax,%ebx @@ -79,8 +65,8 @@ verify_cpu_noamd: movl $0x1,%eax # Does the cpu have what it takes cpuid - andl $REQUIRED_MASK1,%edx - xorl $REQUIRED_MASK1,%edx + andl $REQUIRED_MASK0,%edx + xorl $REQUIRED_MASK0,%edx jnz verify_cpu_no_longmode movl $0x80000000,%eax # See if extended cpuid is implemented @@ -90,8 +76,8 @@ movl $0x80000001,%eax # Does the cpu have what it takes cpuid - andl $REQUIRED_MASK2,%edx - xorl $REQUIRED_MASK2,%edx + andl $REQUIRED_MASK1,%edx + xorl $REQUIRED_MASK1,%edx jnz verify_cpu_no_longmode verify_cpu_sse_test: --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -718,74 +718,25 @@ device_timer.function = hd_times_out; blk_queue_hardsect_size(hd_queue, 512); -#ifdef __i386__ if (!NR_HD) { - extern struct drive_info drive_info; - unsigned char *BIOS = (unsigned char *) &drive_info; - unsigned long flags; - int cmos_disks; - - for (drive=0 ; drive<2 ; drive++) { - hd_info[drive].cyl = *(unsigned short *) BIOS; - hd_info[drive].head = *(2+BIOS); - hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); - hd_info[drive].ctl = *(8+BIOS); - hd_info[drive].lzone = *(unsigned short *) (12+BIOS); - hd_info[drive].sect = *(14+BIOS); -#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp - if (hd_info[drive].cyl && NR_HD == drive) - NR_HD++; -#endif - BIOS += 16; - } - - /* - We query CMOS about hard disks : it could be that - we have a SCSI/ESDI/etc controller that is BIOS - compatible with ST-506, and thus showing up in our - BIOS table, but not register compatible, and therefore - not present in CMOS. - - Furthermore, we will assume that our ST-506 drives - are the primary drives in the system, and - the ones reflected as drive 1 or 2. - - The first drive is stored in the high nibble of CMOS - byte 0x12, the second in the low nibble. This will be - either a 4 bit drive type or 0xf indicating use byte 0x19 - for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. - - Needless to say, a non-zero value means we have - an AT controller hard disk for that drive. - - Currently the rtc_lock is a bit academic since this - driver is non-modular, but someday... ? Paul G. - */ - - spin_lock_irqsave(&rtc_lock, flags); - cmos_disks = CMOS_READ(0x12); - spin_unlock_irqrestore(&rtc_lock, flags); - - if (cmos_disks & 0xf0) { - if (cmos_disks & 0x0f) - NR_HD = 2; - else - NR_HD = 1; - } - } -#endif /* __i386__ */ -#ifdef __arm__ - if (!NR_HD) { - /* We don't know anything about the drive. This means + /* + * We don't know anything about the drive. This means * that you *MUST* specify the drive parameters to the * kernel yourself. + * + * If we were on an i386, we used to read this info from + * the BIOS or CMOS. This doesn't work all that well, + * since this assumes that this is a primary or secondary + * drive, and if we're using this legacy driver, it's + * probably an auxilliary controller added to recover + * legacy data off an ST-506 drive. Either way, it's + * definitely safest to have the user explicitly specify + * the information. */ printk("hd: no drives specified - use hd=cyl,head,sectors" " on kernel command line\n"); - } -#endif - if (!NR_HD) goto out; + } for (drive=0 ; drive < NR_HD ; drive++) { struct gendisk *disk = alloc_disk(64); --- a/include/asm-i386/boot.h +++ b/include/asm-i386/boot.h @@ -1,5 +1,5 @@ -#ifndef _LINUX_BOOT_H -#define _LINUX_BOOT_H +#ifndef _ASM_BOOT_H +#define _ASM_BOOT_H /* Don't touch these, unless you really know what you're doing. */ #define DEF_INITSEG 0x9000 @@ -17,4 +17,4 @@ + (CONFIG_PHYSICAL_ALIGN - 1)) \ & ~(CONFIG_PHYSICAL_ALIGN - 1)) -#endif /* _LINUX_BOOT_H */ +#endif /* _ASM_BOOT_H */ --- /dev/null +++ b/include/asm-i386/bootparam.h @@ -0,0 +1,85 @@ +#ifndef _ASM_BOOTPARAM_H +#define _ASM_BOOTPARAM_H + +#include +#include +#include +#include +#include +#include