5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 #include <sys/types.h>
29 #include <sys/machparam.h>
30 #include <sys/x86_archext.h>
31 #include <sys/systm.h>
32 #include <sys/mach_mmu.h>
33 #include <sys/multiboot.h>
34
35 #if defined(__xpv)
36
37 #include <sys/hypervisor.h>
38 uintptr_t xen_virt_start;
39 pfn_t *mfn_to_pfn_mapping;
40
41 #else /* !__xpv */
42
43 extern multiboot_header_t mb_header;
44 extern int have_cpuid(void);
45
46 #endif /* !__xpv */
47
48 #include <sys/inttypes.h>
49 #include <sys/bootinfo.h>
50 #include <sys/mach_mmu.h>
51 #include <sys/boot_console.h>
52
53 #include "dboot_asm.h"
54 #include "dboot_printf.h"
55 #include "dboot_xboot.h"
56 #include "dboot_elfload.h"
57
58 /*
59 * This file contains code that runs to transition us from either a multiboot
60 * compliant loader (32 bit non-paging) or a XPV domain loader to
61 * regular kernel execution. Its task is to setup the kernel memory image
62 * and page tables.
63 *
64 * The code executes as:
65 * - 32 bits under GRUB (for 32 or 64 bit Solaris)
66 * - a 32 bit program for the 32-bit PV hypervisor
67 * - a 64 bit program for the 64-bit PV hypervisor (at least for now)
68 *
69 * Under the PV hypervisor, we must create mappings for any memory beyond the
70 * initial start of day allocation (such as the kernel itself).
71 *
72 * When on the metal, the mapping between maddr_t and paddr_t is 1:1.
73 * Since we are running in real mode, so all such memory is accessible.
74 */
75
76 /*
77 * Standard bits used in PTE (page level) and PTP (internal levels)
750 /*
751 * build bios reserved memlists
752 */
753 build_rsvdmemlists();
754
755 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
756 /*
757 * build PCI Memory list
758 */
759 map.nr_entries = MAXMAPS;
760 /*LINTED: constant in conditional context*/
761 set_xen_guest_handle(map.buffer, map_buffer);
762 if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &map) != 0)
763 dboot_panic("getting XENMEM_machine_memory_map failed");
764 build_pcimemlists(map_buffer, map.nr_entries);
765 }
766 }
767
768 #else /* !__xpv */
769
770 /*
771 * During memory allocation, find the highest address not used yet.
772 */
773 static void
774 check_higher(paddr_t a)
775 {
776 if (a < next_avail_addr)
777 return;
778 next_avail_addr = RNDUP(a + 1, MMU_PAGESIZE);
779 DBG(next_avail_addr);
780 }
781
782 /*
783 * Walk through the module information finding the last used address.
784 * The first available address will become the top level page table.
785 *
786 * We then build the phys_install memlist from the multiboot information.
787 */
788 static void
789 init_mem_alloc(void)
790 {
796 extern char _end[];
797 int i;
798
799 DBG_MSG("Entered init_mem_alloc()\n");
800 DBG((uintptr_t)mb_info);
801
802 if (mb_info->mods_count > MAX_MODULES) {
803 dboot_panic("Too many modules (%d) -- the maximum is %d.",
804 mb_info->mods_count, MAX_MODULES);
805 }
806 /*
807 * search the modules to find the last used address
808 * we'll build the module list while we're walking through here
809 */
810 DBG_MSG("\nFinding Modules\n");
811 check_higher((paddr_t)(uintptr_t)&_end);
812 for (mod = (mb_module_t *)(mb_info->mods_addr), i = 0;
813 i < mb_info->mods_count;
814 ++mod, ++i) {
815 if (prom_debug) {
816 dboot_printf("\tmodule #%d: %s at: 0x%lx, len 0x%lx\n",
817 i, (char *)(mod->mod_name),
818 (ulong_t)mod->mod_start, (ulong_t)mod->mod_end);
819 }
820 modules[i].bm_addr = mod->mod_start;
821 if (mod->mod_start > mod->mod_end) {
822 dboot_panic("module[%d]: Invalid module start address "
823 "(0x%llx)", i, (uint64_t)mod->mod_start);
824 }
825 modules[i].bm_size = mod->mod_end - mod->mod_start;
826
827 check_higher(mod->mod_end);
828 }
829 bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
830 DBG(bi->bi_modules);
831 bi->bi_module_cnt = mb_info->mods_count;
832 DBG(bi->bi_module_cnt);
833
834 /*
835 * Walk through the memory map from multiboot and build our memlist
836 * structures. Note these will have native format pointers.
837 */
838 DBG_MSG("\nFinding Memory Map\n");
839 DBG(mb_info->flags);
840 max_mem = 0;
841 if (mb_info->flags & 0x40) {
842 int cnt = 0;
843
844 DBG(mb_info->mmap_addr);
845 DBG(mb_info->mmap_length);
846 check_higher(mb_info->mmap_addr + mb_info->mmap_length);
847
848 for (mmap = (mb_memory_map_t *)mb_info->mmap_addr;
849 (uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length;
850 mmap = (mb_memory_map_t *)((uint32_t)mmap + mmap->size
851 + sizeof (mmap->size))) {
852 ++cnt;
853 start = ((uint64_t)mmap->base_addr_high << 32) +
|
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2012 Joyent, Inc. All rights reserved.
27 */
28
29
30 #include <sys/types.h>
31 #include <sys/machparam.h>
32 #include <sys/x86_archext.h>
33 #include <sys/systm.h>
34 #include <sys/mach_mmu.h>
35 #include <sys/multiboot.h>
36 #include <sys/sha1.h>
37
38 #if defined(__xpv)
39
40 #include <sys/hypervisor.h>
41 uintptr_t xen_virt_start;
42 pfn_t *mfn_to_pfn_mapping;
43
44 #else /* !__xpv */
45
46 extern multiboot_header_t mb_header;
47 extern int have_cpuid(void);
48
49 #endif /* !__xpv */
50
51 #include <sys/inttypes.h>
52 #include <sys/bootinfo.h>
53 #include <sys/mach_mmu.h>
54 #include <sys/boot_console.h>
55
56 #include "dboot_asm.h"
57 #include "dboot_printf.h"
58 #include "dboot_xboot.h"
59 #include "dboot_elfload.h"
60
61 #define SHA1_ASCII_LENGTH (SHA1_DIGEST_LENGTH * 2)
62
63 /*
64 * This file contains code that runs to transition us from either a multiboot
65 * compliant loader (32 bit non-paging) or a XPV domain loader to
66 * regular kernel execution. Its task is to setup the kernel memory image
67 * and page tables.
68 *
69 * The code executes as:
70 * - 32 bits under GRUB (for 32 or 64 bit Solaris)
71 * - a 32 bit program for the 32-bit PV hypervisor
72 * - a 64 bit program for the 64-bit PV hypervisor (at least for now)
73 *
74 * Under the PV hypervisor, we must create mappings for any memory beyond the
75 * initial start of day allocation (such as the kernel itself).
76 *
77 * When on the metal, the mapping between maddr_t and paddr_t is 1:1.
78 * Since we are running in real mode, so all such memory is accessible.
79 */
80
81 /*
82 * Standard bits used in PTE (page level) and PTP (internal levels)
755 /*
756 * build bios reserved memlists
757 */
758 build_rsvdmemlists();
759
760 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
761 /*
762 * build PCI Memory list
763 */
764 map.nr_entries = MAXMAPS;
765 /*LINTED: constant in conditional context*/
766 set_xen_guest_handle(map.buffer, map_buffer);
767 if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &map) != 0)
768 dboot_panic("getting XENMEM_machine_memory_map failed");
769 build_pcimemlists(map_buffer, map.nr_entries);
770 }
771 }
772
773 #else /* !__xpv */
774
775 static uint8_t
776 dboot_a2h(char v)
777 {
778 if (v >= 'a')
779 return (v - 'a' + 0xa);
780 else if (v >= 'A')
781 return (v - 'A' + 0xa);
782 else if (v >= '0')
783 return (v - '0');
784 else
785 dboot_panic("bad ASCII hex character %c\n", v);
786
787 return (0);
788 }
789
790 static void
791 digest_a2h(const char *ascii, uint8_t *digest)
792 {
793 unsigned int i;
794
795 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
796 digest[i] = dboot_a2h(ascii[i * 2]) << 4;
797 digest[i] |= dboot_a2h(ascii[i * 2 + 1]);
798 }
799 }
800
801 /*
802 * Generate a SHA-1 hash of the first len bytes of image, and compare it with
803 * the ASCII-format hash found in the 40-byte buffer at ascii. If they
804 * match, return 0, otherwise -1. This works only for images smaller than
805 * 4 GB, which should not be a problem.
806 */
807 static int
808 check_image_hash(const char *ascii, const void *image, size_t len)
809 {
810 SHA1_CTX ctx;
811 uint8_t digest[SHA1_DIGEST_LENGTH];
812 uint8_t baseline[SHA1_DIGEST_LENGTH];
813 unsigned int i;
814
815 digest_a2h(ascii, baseline);
816
817 SHA1Init(&ctx);
818 SHA1Update(&ctx, image, len);
819 SHA1Final(digest, &ctx);
820
821 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
822 if (digest[i] != baseline[i])
823 return (-1);
824 }
825
826 return (0);
827 }
828
829 static void
830 check_images(void)
831 {
832 int i;
833 char *hashes;
834 mb_module_t *mod, *hashmod;
835 char *hash;
836 char displayhash[SHA1_ASCII_LENGTH + 1];
837 size_t hashlen;
838 size_t len;
839
840 /*
841 * A brief note on lengths and sizes: GRUB, for reasons unknown, passes
842 * the address of the last valid byte in a module plus 1 as mod_end.
843 * This is of course a bug; the multiboot specification simply states
844 * that mod_start and mod_end "contain the start and end addresses of
845 * the boot module itself" which is pretty obviously not what GRUB is
846 * doing. However, fixing it requires that not only this code be
847 * changed but also that other code consuming this value and values
848 * derived from it be fixed, and that the kernel and GRUB must either
849 * both have the bug or neither. While there are a lot of combinations
850 * that will work, there are also some that won't, so for simplicity
851 * we'll just cope with the bug. That means we won't actually hash the
852 * byte at mod_end, and we will expect that mod_end for the hash file
853 * itself is one greater than some multiple of 41 (40 bytes of ASCII
854 * hash plus a newline for each module).
855 */
856
857 if (mb_info->mods_count > 1) {
858 mod = (mb_module_t *)mb_info->mods_addr;
859 hashmod = mod + (mb_info->mods_count - 1);
860 hashes = (char *)hashmod->mod_start;
861 hashlen = (size_t)(hashmod->mod_end - hashmod->mod_start);
862 hash = hashes;
863 if (prom_debug) {
864 dboot_printf("Hash module found at %lx size %lx\n",
865 (ulong_t)hashes, (ulong_t)hashlen);
866 }
867 } else {
868 DBG_MSG("Skipping hash check; no hash module found.\n");
869 return;
870 }
871
872 for (mod = (mb_module_t *)(mb_info->mods_addr), i = 0;
873 i < mb_info->mods_count - 1; ++mod, ++i) {
874 if ((hash - hashes) + SHA1_ASCII_LENGTH + 1 > hashlen) {
875 dboot_printf("Short hash module of length 0x%lx bytes; "
876 "skipping hash checks\n", (ulong_t)hashlen);
877 break;
878 }
879
880 (void) memcpy(displayhash, hash, SHA1_ASCII_LENGTH);
881 displayhash[SHA1_ASCII_LENGTH] = '\0';
882 if (prom_debug) {
883 dboot_printf("Checking hash for module %d [%s]: ",
884 i, displayhash);
885 }
886
887 len = mod->mod_end - mod->mod_start; /* see above */
888 if (check_image_hash(hash, (void *)mod->mod_start, len) != 0) {
889 dboot_panic("SHA-1 hash mismatch on %s; expected %s\n",
890 (char *)mod->mod_name, displayhash);
891 } else {
892 DBG_MSG("OK\n");
893 }
894 hash += SHA1_ASCII_LENGTH + 1;
895 }
896 }
897
898 /*
899 * During memory allocation, find the highest address not used yet.
900 */
901 static void
902 check_higher(paddr_t a)
903 {
904 if (a < next_avail_addr)
905 return;
906 next_avail_addr = RNDUP(a + 1, MMU_PAGESIZE);
907 DBG(next_avail_addr);
908 }
909
910 /*
911 * Walk through the module information finding the last used address.
912 * The first available address will become the top level page table.
913 *
914 * We then build the phys_install memlist from the multiboot information.
915 */
916 static void
917 init_mem_alloc(void)
918 {
924 extern char _end[];
925 int i;
926
927 DBG_MSG("Entered init_mem_alloc()\n");
928 DBG((uintptr_t)mb_info);
929
930 if (mb_info->mods_count > MAX_MODULES) {
931 dboot_panic("Too many modules (%d) -- the maximum is %d.",
932 mb_info->mods_count, MAX_MODULES);
933 }
934 /*
935 * search the modules to find the last used address
936 * we'll build the module list while we're walking through here
937 */
938 DBG_MSG("\nFinding Modules\n");
939 check_higher((paddr_t)(uintptr_t)&_end);
940 for (mod = (mb_module_t *)(mb_info->mods_addr), i = 0;
941 i < mb_info->mods_count;
942 ++mod, ++i) {
943 if (prom_debug) {
944 dboot_printf("\tmodule #%d: %s at: 0x%lx, end 0x%lx\n",
945 i, (char *)(mod->mod_name),
946 (ulong_t)mod->mod_start, (ulong_t)mod->mod_end);
947 }
948 modules[i].bm_addr = mod->mod_start;
949 if (mod->mod_start > mod->mod_end) {
950 dboot_panic("module[%d]: Invalid module start address "
951 "(0x%llx)", i, (uint64_t)mod->mod_start);
952 }
953 modules[i].bm_size = mod->mod_end - mod->mod_start;
954
955 check_higher(mod->mod_end);
956 }
957 bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
958 DBG(bi->bi_modules);
959 bi->bi_module_cnt = mb_info->mods_count;
960 DBG(bi->bi_module_cnt);
961
962 check_images();
963
964 /*
965 * Walk through the memory map from multiboot and build our memlist
966 * structures. Note these will have native format pointers.
967 */
968 DBG_MSG("\nFinding Memory Map\n");
969 DBG(mb_info->flags);
970 max_mem = 0;
971 if (mb_info->flags & 0x40) {
972 int cnt = 0;
973
974 DBG(mb_info->mmap_addr);
975 DBG(mb_info->mmap_length);
976 check_higher(mb_info->mmap_addr + mb_info->mmap_length);
977
978 for (mmap = (mb_memory_map_t *)mb_info->mmap_addr;
979 (uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length;
980 mmap = (mb_memory_map_t *)((uint32_t)mmap + mmap->size
981 + sizeof (mmap->size))) {
982 ++cnt;
983 start = ((uint64_t)mmap->base_addr_high << 32) +
|