Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/i386/libi386/biosmemdisk.c
34869 views
1
/*-
2
* Copyright (c) 2020 Richard Russo <[email protected]>
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*/
6
7
/*
8
* Source of information: https://repo.or.cz/syslinux.git
9
*
10
* Implements the MEMDISK protocol from syslinux, found in doc/memdisk.txt
11
* (search MEMDISK info structure). Since we validate the pointer to the mBFT, a
12
* minimum version of 3.85 is needed. Note: All this could be done in the
13
* kernel, since we don't have hooks to use this inside the boot loader. The
14
* details of these structures can be found in memdisk/memdisk.inc (search
15
* for mBFT).
16
*
17
* The kernel could just grab the mBFT table, but instead relies on us finding
18
* it and setting the right env variables.
19
*/
20
#include <stand.h>
21
#include <machine/stdarg.h>
22
#include <bootstrap.h>
23
#include <btxv86.h>
24
#include "libi386.h"
25
26
#include "platform/acfreebsd.h"
27
#include "acconfig.h"
28
#define ACPI_SYSTEM_XFACE
29
#include "actypes.h"
30
#include "actbl.h"
31
32
struct memdisk_info {
33
uint32_t mdi_13h_hook_ptr; /* not included in mdi_length! */
34
uint16_t mdi_length;
35
uint8_t mdi_minor;
36
uint8_t mdi_major;
37
uint32_t mdi_disk_ptr;
38
uint32_t mdi_disk_sectors;
39
uint32_t mdi_far_ptr_cmdline;
40
uint32_t mdi_old_int13h;
41
uint32_t mdi_old_int15h;
42
uint16_t mdi_dos_mem_before;
43
uint8_t mdi_boot_loader_id;
44
uint8_t mdi_sector_size; /* Code below assumes this is last */
45
} __attribute__((packed));
46
47
struct safe_13h_hook {
48
char sh_jmp[3];
49
char sh_id[8];
50
char sh_vendor[8];
51
uint16_t sh_next_offset;
52
uint16_t sh_next_segment;
53
uint32_t sh_flags;
54
uint32_t sh_mbft;
55
} __attribute__((packed));
56
57
/*
58
* Maximum length of INT 13 entries we'll chase. Real disks are on this list,
59
* potentially, so we may have to look through them to find the memdisk.
60
*/
61
#define MEMDISK_MAX 32
62
63
/*
64
* Scan for MEMDISK virtual block devices
65
*/
66
void
67
biosmemdisk_detect(void)
68
{
69
char line[80], scratch[80];
70
int hook = 0, count = 0, sector_size;
71
uint16_t segment, offset;
72
struct safe_13h_hook *probe;
73
ACPI_TABLE_HEADER *mbft;
74
uint8_t *cp, sum;
75
struct memdisk_info *mdi;
76
77
/*
78
* Walk through the int13 handler linked list, looking for possible
79
* MEMDISKs.
80
*
81
* The max is arbitrary to ensure termination.
82
*/
83
offset = *(uint16_t *)PTOV(0x13 * 4);
84
segment = *(uint16_t *)PTOV(0x13 * 4 + 2);
85
while (hook < MEMDISK_MAX && !(segment == 0 && offset == 0)) {
86
/*
87
* Walk the linked list, making sure each node has the right
88
* signature and only looking at MEMDISK nodes.
89
*/
90
probe = (struct safe_13h_hook *)PTOV(segment * 16 + offset);
91
if (memcmp(probe->sh_id, "$INT13SF", sizeof(probe->sh_id)) != 0) {
92
printf("Found int 13h unsafe hook at %p (%x:%x)\n",
93
probe, segment, offset);
94
break;
95
}
96
if (memcmp(probe->sh_vendor, "MEMDISK ", sizeof(probe->sh_vendor)) != 0)
97
goto end_of_loop;
98
99
/*
100
* If it is a memdisk, make sure the mBFT signature is correct
101
* and its checksum is right.
102
*/
103
mbft = (ACPI_TABLE_HEADER *)PTOV(probe->sh_mbft);
104
if (memcmp(mbft->Signature, "mBFT", sizeof(mbft->Signature)) != 0)
105
goto end_of_loop;
106
sum = 0;
107
cp = (uint8_t *)mbft;
108
for (int idx = 0; idx < mbft->Length; ++idx)
109
sum += *(cp + idx);
110
if (sum != 0)
111
goto end_of_loop;
112
113
/*
114
* The memdisk info follows the ACPI_TABLE_HEADER in the mBFT
115
* section. If the sector size is present and non-zero use it
116
* otherwise assume 512.
117
*/
118
mdi = (struct memdisk_info *)PTOV(probe->sh_mbft + sizeof(*mbft));
119
sector_size = 512;
120
if (mdi->mdi_length + sizeof(mdi->mdi_13h_hook_ptr) >= sizeof(*mdi) &&
121
mdi->mdi_sector_size != 0)
122
sector_size = 1 << mdi->mdi_sector_size;
123
124
printf("memdisk %d.%d disk at %#x (%d sectors = %d bytes)\n",
125
mdi->mdi_major, mdi->mdi_minor, mdi->mdi_disk_ptr,
126
mdi->mdi_disk_sectors, mdi->mdi_disk_sectors * sector_size);
127
128
snprintf(line, sizeof(line), "hint.md.%d.physaddr", count);
129
snprintf(scratch, sizeof(scratch), "0x%08x", mdi->mdi_disk_ptr);
130
setenv(line, scratch, 1);
131
snprintf(line, sizeof(line), "hint.md.%d.len", count);
132
snprintf(scratch, sizeof(scratch), "%d", mdi->mdi_disk_sectors * sector_size);
133
setenv(line, scratch, 1);
134
count++;
135
end_of_loop:
136
hook++;
137
offset = probe->sh_next_offset;
138
segment = probe->sh_next_segment;
139
}
140
}
141
142