Low-level PC Info Retrieval
You
in MSDOS on the PC I want to get some low level info about the computer, for example
- The amount of RAM in the system
- The CPU
- Anything about the BIOS and motherboard
I am using DJGPP to write C code.
ChatGPT
Using DJGPP, you can retrieve low-level system information in MS-DOS by interacting with BIOS interrupts, the DOS API, and direct hardware queries. Here’s how you can gather some of the information you’re looking for:
1. Getting Total System RAM
You can use INT 12h to get the conventional memory size (first 640 KB) and INT 15h, AX=E801h or AX=E820h to get extended memory (beyond 1MB).
Example (Conventional Memory - INT 12h)
#include <dos.h>
#include <stdio.h>
int main() {
union REGS regs;
regs.h.ah = 0x12;
int86(0x12, ®s, ®s);
printf("Conventional Memory: %d KB\n", regs.x.ax);
return 0;
}
Example (Extended Memory - INT 15h, E801h)
#include <dos.h>
#include <stdio.h>
int main() {
union REGS regs;
regs.x.ax = 0xE801;
int86(0x15, ®s, ®s);
if (regs.x.ax || regs.x.bx) { // If BIOS supports it
int extmem = (regs.x.ax * 64) + (regs.x.bx * 1024);
printf("Extended Memory: %d KB\n", extmem);
} else {
printf("Extended Memory query failed.\n");
}
return 0;
}
If that doesn’t work, use INT 15h, AX=E820h for a more detailed memory map.
2. Detecting the CPU Type
DJGPP provides the __djgpp_cpuid
variable, but you can also manually query CPUID (if supported) or check flags.
Example (Checking CPU using CPUID)
#include <stdio.h>
int main() {
int eax, ebx, ecx, edx;
__asm__ __volatile__ (
"mov $0, %%eax\n\t"
"cpuid\n\t"
"mov %%eax, %0\n\t"
"mov %%ebx, %1\n\t"
"mov %%ecx, %2\n\t"
"mov %%edx, %3\n\t"
: "=r" (eax), "=r" (ebx), "=r" (ecx), "=r" (edx)
:
: "eax", "ebx", "ecx", "edx"
);
printf("CPU Vendor: %.4s%.4s%.4s\n", (char*)&ebx, (char*)&edx, (char*)&ecx);
return 0;
}
This retrieves the CPU vendor string (e.g., “GenuineIntel” or “AuthenticAMD”).
3. Getting BIOS and Motherboard Info
You can retrieve BIOS-related information from the BIOS Data Area (BDA) at segment 40h.
Example (BIOS Manufacturer Date and Model from F000:FFF5)
#include <stdio.h>
char* get_bios_date() {
return (char*)0xF000FFF5;
}
int main() {
printf("BIOS Date: %s\n", get_bios_date());
return 0;
}
This returns the BIOS release date as a string.
For more detailed BIOS information, scan the BIOS ROM for identifiers, or use INT 1Ah (real-time clock) to get some system details.
4. Getting the Motherboard Manufacturer
If your BIOS supports DMI (Desktop Management Interface), you can use INT 15h, AX=0xD000 to query SMBIOS.
However, older systems may not support this, and you might need to parse raw BIOS data.
Final Thoughts
- Some of these methods may not work on every system, especially very old PCs without CPUID or SMBIOS support.
- INT 15h
- Reading
Would you like more advanced methods, such as reading PCI configuration space or scanning the BIOS ROM for specific signatures?
ChatGPT
Getting a Detailed Memory Map Using INT 15h, AX=E820h
The BIOS interrupt INT 15h, AX=E820h provides a detailed memory map of the system. Unlike older methods (such as INT 12h or INT 15h, AX=E801h), which only report total memory, E820h returns a list of memory regions, including reserved, usable, and special memory areas.
How INT 15h, AX=E820h Works
- You call
- You pass a memory buffer for the BIOS to fill with information.
- You retrieve multiple memory entries by calling it repeatedly with an index.
- Each entry describes a specific memory range and its type.
This method allows you to:
- Identify all
- Detect reserved memory areas (e.g., BIOS, MMIO regions).
- Detect ACPI and other special areas.
Memory Map Entry Structure
Each call to INT 15h, AX=E820h returns a memory map entry in the following format:
Offset | Size | Description |
---|---|---|
0x00 | 4 | Base address (low 32 bits) |
0x04 | 4 | Base address (high 32 bits) |
0x08 | 4 | Length in bytes (low 32 bits) |
0x0C | 4 | Length in bytes (high 32 bits) |
0x10 | 4 | Type (1 = usable, other = reserved) |
0x14 | 4 | (Optional) Extended attributes |
The type field tells you how the memory can be used:
- 1 → Usable (RAM)
- 2 → Reserved (BIOS, MMIO)
- 3 → ACPI reclaimable memory
- 4 → ACPI NVS memory (used for power management)
- 5 → Defective memory (bad RAM)
Example C Code Using DJGPP
Since DJGPP runs in protected mode, we need to switch to real mode (using a DOS extender like CWSDPMI) or use a DOS interrupt call via int86x.
Here’s how you can retrieve the memory map:
#include <dos.h>
#include <stdio.h>
struct E820_Entry {
unsigned long base_low;
unsigned long base_high;
unsigned long length_low;
unsigned long length_high;
unsigned long type;
} __attribute__((packed));
int main() {
struct E820_Entry entry;
union REGS regs;
struct SREGS sregs;
unsigned long contID = 0;
printf("Base Address | Length | Type\n");
printf("-------------------+-------------------+------\n");
do {
regs.x.ax = 0xE820; // Function: Get System Memory Map
regs.x.cx = sizeof(entry);
regs.x.edx = 0x534D4150; // 'SMAP' magic number
regs.x.ebx = contID; // Continuation ID (0 on first call)
sregs.es = FP_SEG(&entry);
regs.x.di = FP_OFF(&entry);
int86x(0x15, ®s, ®s, &sregs); // Call INT 15h
if (regs.x.eflags & 1) break; // Check carry flag (CF) for errors
contID = regs.x.ebx; // Store continuation ID for next call
printf("%08lX%08lX | %08lX%08lX | %lu\n",
entry.base_high, entry.base_low,
entry.length_high, entry.length_low,
entry.type);
} while (contID != 0); // Continue until EBX returns 0
return 0;
}
Explanation of Code
- We define a struct E820_Entry
- We set up registers for the BIOS call
- AX = E820h
- CX = sizeof(entry)
- EDX = ‘SMAP’
- EBX = contID
- ES:DI
- We call INT 15h using int86x
- We check the carry flag (CF)
- If set, the BIOS call failed.
- We loop until EBX returns 0
Interpreting the Output
Example output might look like this:
Base Address | Length | Type
-------------------+-------------------+------
0000000000000000 | 000000000009FC00 | 1 (Usable)
000000000009FC00 | 0000000000000400 | 2 (Reserved - BIOS)
00000000000F0000 | 0000000000010000 | 2 (Reserved - BIOS)
0000000000100000 | 0000000003FF0000 | 1 (Usable RAM)
00000000FFFC0000 | 0000000000040000 | 2 (Reserved - BIOS)
This shows:
- Conventional RAM
- BIOS Reserved Areas
- Usable Extended RAM
Advantages of Using INT 15h, AX=E820h
- ✅ More accurate than INT 12h or E801h → These older methods only return total RAM and might not account for reserved memory.
- ✅ Provides multiple memory regions → Helps OS developers manage usable vs. reserved memory.
- ✅ Works on most BIOSes from 1995 onward → Newer machines with UEFI might require different methods.
Limitations
❌ Requires BIOS support → Some old PCs (pre-1995) don’t support it.❌ Must handle multiple entries → Unlike INT 12h, which just gives a single value.❌ Protected mode limitations in DJGPP → Requires int86x
and segment register handling.
Would you like an explanation on how to use INT 1Ah for RTC BIOS time or PCI BIOS functions for motherboard detection?
You
yes
ChatGPT
Getting BIOS and Motherboard Information in MS-DOS using C (DJGPP)
To retrieve low-level system information like BIOS details, real-time clock (RTC), and motherboard details, we can use BIOS interrupts such as INT 1Ah and PCI BIOS functions (INT 1Ah, AX=B101h).
- Getting the Real-Time Clock (RTC) with INT 1Ah
The real-time clock (RTC) is stored in the CMOS (Complementary Metal-Oxide Semiconductor) chip and keeps track of the system’s date and time, even when powered off.
How INT 1Ah Works
- Call INT 1Ah with AH = 00h to get the current time.
- The BIOS returns:
- CH
- CL
- DH
- Convert the BCD values to decimal.
Example C Code to Get Time
#include <dos.h>
#include <stdio.h>
int bcd_to_decimal(int bcd) {
return ((bcd >> 4) * 10) + (bcd & 0x0F);
}
int main() {
union REGS regs;
// Call INT 1Ah, AH = 00h (Get RTC Time)
regs.h.ah = 0x00;
int86(0x1A, ®s, ®s);
int hours = bcd_to_decimal(regs.h.ch);
int minutes = bcd_to_decimal(regs.h.cl);
int seconds = bcd_to_decimal(regs.h.dh);
printf("Current RTC Time: %02d:%02d:%02d\n", hours, minutes, seconds);
return 0;
}
Example Output
Current RTC Time: 14:23:45
- Getting Motherboard and BIOS Information
Some details about the BIOS and motherboard can be retrieved using INT 1Ah, AX=B101h (PCI BIOS services) or by reading the BIOS Data Area (BDA) at 0xF000:0FFF.
Detecting PCI BIOS with INT 1Ah
If your system has PCI devices, the PCI BIOS provides information about the system, including motherboard chipset details.
How INT 1Ah, AX=B101h Works
- Call
- If PCI BIOS is available, it returns:
- BX = “PCI” signature (0x20494350)
- CL = PCI hardware version
- CH = Number of PCI buses
- ES:DI = Pointer to PCI Service Structure
Example C Code for PCI BIOS Detection
#include <dos.h>
#include <stdio.h>
int main() {
union REGS regs;
// Call INT 1Ah, AX = B101h (PCI BIOS Present)
regs.x.ax = 0xB101;
int86(0x1A, ®s, ®s);
// Check if PCI BIOS is available
if (regs.x.bx == 0x20494350) { // 'PCI ' signature
printf("PCI BIOS detected\n");
printf("PCI Hardware Version: %d.%d\n", regs.h.ch, regs.h.cl);
printf("Number of PCI Buses: %d\n", regs.h.ch);
} else {
printf("PCI BIOS not available\n");
}
return 0;
}
Example Output
PCI BIOS detected
PCI Hardware Version: 2.1
Number of PCI Buses: 1
This indicates that:
- The system supports PCI BIOS.
- The PCI hardware version is
- There is
- Reading BIOS Manufacturer and Motherboard Details
The BIOS manufacturer string is stored in the BIOS ROM at segment 0xF000.
Reading BIOS Information from Memory
- BIOS Date
- BIOS Manufacturer
Example C Code to Read BIOS Date
#include <stdio.h>
#include <dos.h>
int main() {
char far *bios_date = (char far *)0xF000FFF5; // Standard location of BIOS date
printf("BIOS Date: %.8s\n", bios_date);
return 0;
}
Example Output
BIOS Date: 09/14/99
This indicates that the BIOS was last updated on September 14, 1999.
Summary
Method | Purpose |
---|---|
INT 1Ah, AH=00h | Get RTC time |
INT 1Ah, AX=B101h | Detect PCI BIOS |
0xF000:0FFF | Read BIOS date |
E820h | Get memory map |
Would you like to explore CPU detection next (e.g., CPUID)?
You
ChatGPT
Reading the BIOS Manufacturer String in MS-DOS with DJGPP
How to Get the BIOS Manufacturer Information
The BIOS Manufacturer is often stored as ASCII text in the BIOS ROM, usually in the F000:0000–F000:FFFF segment of memory (the BIOS ROM area). However, its exact location varies by manufacturer. Some BIOS versions store a human-readable string at 0xF000:FFF5, alongside the BIOS date.
Since DJGPP runs in protected mode, we must use a DOS interrupt or switch to real-mode memory access to read from this area.
Method 1: Direct Memory Access (Only Works in Real Mode)
If you were writing a real-mode DOS program (e.g., using Turbo C or OpenWatcom), you could access the BIOS ROM directly using a far pointer:
#include <stdio.h>
#include <dos.h>
int main() {
char far *bios_string = (char far *)0xF000E000; // Possible location in BIOS ROM
printf("BIOS String: %.16s\n", bios_string); // Print first 16 characters
return 0;
}
However, this does not work in DJGPP, since DJGPP runs in a 32-bit protected mode environment.
Method 2: Using the DOS Real-Mode Memory Transfer
Since DJGPP runs in protected mode, we need to use int 0x15 (BIOS memory functions) or DPMI (DOS Protected Mode Interface) to access real-mode memory.
Example: Using int86() to Get BIOS Information
This code calls a DOS interrupt (INT 15h) to get the BIOS memory area.
#include <stdio.h>
#include <dos.h>
int main() {
union REGS regs;
// Set function: INT 15h, AX=E820h (Get Memory Map)
regs.x.ax = 0xE820;
regs.x.cx = 0; // Size of buffer
regs.x.dx = 0x534D4150; // 'SMAP' signature
int86(0x15, ®s, ®s);
if (regs.x.eax == 0x534D4150) { // Check if 'SMAP' returned correctly
printf("BIOS Memory Map Function Available\n");
} else {
printf("BIOS Memory Map Function Not Supported\n");
}
return 0;
}
This doesn’t directly read the BIOS string but verifies if we can access BIOS memory-mapped information.
To directly get the BIOS manufacturer, you’d need a DPMI real-mode memory call, which requires DPMI services.
Would you like an example using DPMI real-mode calls to fetch BIOS data?
Now, About CPUID
The CPUID instruction provides detailed information about the CPU, such as:
- Vendor string
- Processor family, model, and stepping
- Feature flags
CPUID is only available on 486+ processors, so it must be checked first.
How to Use CPUID
- Set EAX to a function number
- Execute CPUID instruction
- Read back EAX, EBX, ECX, and EDX
Example CPUID in DJGPP
DJGPP does not allow inline assembly with cpuid
directly. Instead, we must use inline assembly with GCC extended syntax:
#include <stdio.h>
void cpuid(int code, unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d) {
__asm__ __volatile__ (
"cpuid"
: "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
: "a"(code)
);
}
int main() {
unsigned int eax, ebx, ecx, edx;
// CPUID function 0: Get vendor ID
cpuid(0, &eax, &ebx, &ecx, &edx);
char vendor[13];
*((unsigned int*)&vendor[0]) = ebx;
*((unsigned int*)&vendor[4]) = edx;
*((unsigned int*)&vendor[8]) = ecx;
vendor[12] = '\0';
printf("CPU Vendor: %s\n", vendor);
return 0;
}
Example Output
CPU Vendor: GenuineIntel
If running on an AMD CPU:
CPU Vendor: AuthenticAMD
Would you like more details on checking CPU features (e.g., MMX, SSE, etc.)?
You
in MSDOS on the PC I want to get some low level info about the computer, for example
The amount of RAM in the system The CPU Anything about the BIOS and motherboard
I am now using Turbo C 3.0 in DOS to write C code.
ChatGPT
Great! Since you’re now using Turbo C 3.0 in MS-DOS, you can access low-level system information like the amount of RAM, CPU type, and BIOS using interrupts and direct memory access.
Here’s how you can get this information using Turbo C 3.0:
- Getting the Amount of RAM
MS-DOS provides an interrupt for getting memory information:
- INT 12h
Getting the Total RAM with INT 12h
#include <dos.h>
#include <stdio.h>
int main() {
union REGS regs;
// Call INT 12h to get the amount of installed RAM
regs.h.ah = 0x00;
int86(0x12, ®s, ®s);
// The total memory is in the AX register (in KB)
printf("Total RAM: %u KB\n", regs.x.ax);
return 0;
}
Explanation:
- INT 12h
- AX register
- Detecting the CPU Type
The CPUID instruction is not directly available in Turbo C 3.0, but you can still detect the CPU type using the ID string or vendor information that INT 15h (Extended BIOS functions) provides.
To get basic CPU information, Turbo C 3.0 can use INT 15h, AX=87h:
Getting CPU Information (Vendor)
#include <dos.h>
#include <stdio.h>
int main() {
union REGS regs;
char vendor[13];
// Call INT 15h, AX=87h to get CPU information
regs.x.ax = 0x8700;
int86(0x15, ®s, ®s);
// Return the CPU Vendor string from the DX register
*((unsigned int*)&vendor[0]) = regs.x.dx;
*((unsigned int*)&vendor[4]) = regs.x.bx;
*((unsigned int*)&vendor[8]) = regs.x.cx;
vendor[12] = '\0';
printf("CPU Vendor: %s\n", vendor);
return 0;
}
Explanation:
- INT 15h, AX=87h
- The
- Getting BIOS Information
The BIOS Manufacturer String and other related information can be retrieved by reading the BIOS data area (located at segment 0xF000).
You can directly access BIOS data using a far pointer to read the BIOS version or manufacturer.
Getting BIOS Date and Manufacturer
#include <stdio.h>
#include <dos.h>
int main() {
char far *bios_string = (char far *)0xF000E000; // Possible location in BIOS ROM
char far *bios_date = (char far *)0xF000FFF5; // Standard location of BIOS date
printf("BIOS Manufacturer: %.16s\n", bios_string);
printf("BIOS Date: %.8s\n", bios_date);
return 0;
}
Explanation:
- 0xF000E000
- 0xF000FFF5
- The string length is limited to the maximum readable portion from memory, typically
- Getting Motherboard Information
Motherboard-specific information is typically harder to retrieve directly from DOS, as there is no standard interrupt for querying motherboard details. However, you can use INT 1Ah (BIOS interrupt for PCI) for some PCI information if your motherboard supports it.
For basic motherboard information, BIOS Interrupts like INT 1Ah can provide details about the PCI system.
Checking for PCI Information via INT 1Ah
#include <stdio.h>
#include <dos.h>
int main() {
union REGS regs;
// Call INT 1Ah, AX=B101h to check PCI system info
regs.x.ax = 0xB101;
int86(0x1A, ®s, ®s);
if (regs.x.bx == 0x20494350) { // Check for 'PCI ' signature
printf("PCI BIOS detected\n");
} else {
printf("PCI BIOS not available\n");
}
return 0;
}
Explanation:
- INT 1Ah, AX=0xB101
- The
Summary of Key Interrupts for Low-Level Info:
Info Type | Interrupt | Function |
---|---|---|
Total RAM | INT 12h | Returns total RAM in KB (in AX) |
CPU Vendor | INT 15h, AX=87h | Returns CPU vendor string in DX, BX, CX |
BIOS Manufacturer | Far pointer at 0xF000E000 | Reads BIOS Manufacturer String |
BIOS Date | Far pointer at 0xF000FFF5 | Reads BIOS Date String |
PCI Info | INT 1Ah, AX=B101h | Detects PCI BIOS availability |
These are the methods you can use to get the RAM size, CPU information, and BIOS/motherboard details in Turbo C 3.0 under MS-DOS. Let me know if you want to dive deeper into any specific area!
You
what can I read from the PCI BIOS? Can I read the strings of text the BIOS normally displays at boot?
ChatGPT
Accessing PCI BIOS Information
The PCI BIOS (part of the system BIOS responsible for managing PCI devices) can provide several pieces of information about the system’s hardware, particularly related to PCI devices (like graphics cards, network adapters, etc.). However, reading strings of text displayed during boot (like the BIOS POST screen) is a bit different and typically not available through PCI BIOS or standard BIOS calls.
Let’s break it down:
- PCI BIOS Information
PCI BIOS provides low-level information related to the PCI devices installed in the system. Some common types of information you can get from the PCI BIOS include:
- List of PCI Devices
- Device Vendor ID
- Device Class Code
- PCI Configuration Space
To access PCI BIOS information in real mode (which is how Turbo C 3.0 runs), you’d typically use INT 1Ah, but this doesn’t directly allow you to access strings like those shown on the boot screen. Here’s what you can typically retrieve:
Reading PCI Information via INT 1Ah
The PCI BIOS provides access to device information through INT 1Ah, and here’s how you can query it:
#include <stdio.h>
#include <dos.h>
int main() {
union REGS regs;
unsigned int vendorID, deviceID;
// Call INT 1Ah, AX=0xB101 to get PCI information
regs.x.ax = 0xB101; // PCI BIOS signature
int86(0x1A, ®s, ®s);
if (regs.x.bx == 0x20494350) { // Check for 'PCI ' signature
printf("PCI BIOS found!\n");
// Call the PCI function to get a device's vendor ID and device ID
regs.x.ax = 0xB100; // Function to get device info
regs.x.bx = 0x0000; // Start with the first device
int86(0x1A, ®s, ®s);
vendorID = regs.x.cx; // Vendor ID in CX
deviceID = regs.x.dx; // Device ID in DX
printf("Vendor ID: 0x%04X\n", vendorID);
printf("Device ID: 0x%04X\n", deviceID);
} else {
printf("PCI BIOS not found!\n");
}
return 0;
}
Explanation:
- INT 1Ah
- AX=0xB101
- AX=0xB100
However, this approach focuses on querying PCI devices rather than reading BIOS messages shown during boot.
- Reading BIOS Text Displayed at Boot
The text that is displayed during the POST (Power-On Self-Test) phase of booting, such as the manufacturer logo, memory check, and device detection messages, is typically generated by the BIOS during the boot sequence. Unfortunately, there is no simple way to directly read those strings using BIOS interrupts in real mode, especially in Turbo C.
Here are the primary reasons:
- BIOS screen output
- BIOS POST
- No interrupt
Can You Capture Boot Messages?
To capture the messages displayed during the BIOS POST phase, you would need to either:
- Log output during boot
- Modify the BIOS
Alternative Approaches to Get BIOS Information (Without POST Output)
While you can’t directly capture the POST boot text from the BIOS, there are other ways to get low-level system information about the BIOS, motherboard, and system setup.
- BIOS Manufacturer and Version
- You can access the
- Motherboard Info
- While there’s no specific BIOS interrupt for
- Serial Numbers
Summary
- PCI Information
- BIOS Strings
- Boot Messages
Let me know if you’d like to dive deeper into any of these topics or need further assistance!
You
Can I read the motherboard type and bios revision and manufacturer from anywhere?
ChatGPT
In MS-DOS, there is no simple, standardized method to directly read detailed motherboard type and BIOS revision/manufacturer like you would expect in modern systems with ACPI or SMBIOS. However, there are some methods you can use to gather BIOS and system information, especially related to the BIOS manufacturer and revision. Let’s explore these methods in more detail:
- BIOS Manufacturer and Revision
You can often retrieve BIOS manufacturer and BIOS version/revision from certain memory locations in the BIOS ROM. This information is available in far memory segments starting from 0xF000, which is where the BIOS ROM is typically located.
Reading BIOS Manufacturer and Version
- BIOS Manufacturer
- BIOS Revision/Version
Here’s an example of how you might read these values using Turbo C 3.0:
#include <stdio.h>
#include <dos.h>
int main() {
char far *bios_manufacturer = (char far *)0xF000E000; // Manufacturer at this address
char far *bios_revision = (char far *)0xF000FFE0; // Revision/Version at this address
// Print the Manufacturer and Revision string (ensure the string is null-terminated)
printf("BIOS Manufacturer: %.16s\n", bios_manufacturer);
printf("BIOS Revision: %.8s\n", bios_revision);
return 0;
}
Explanation:
- 0xF000E000
- 0xF000FFE0
What You Get:
- BIOS Manufacturer
- BIOS Revision
- PCI BIOS and Motherboard Information
While PCI BIOS doesn’t provide direct motherboard information, it can give you clues about the PCI devices (e.g., integrated graphics, network cards, etc.) that are often part of the motherboard. Some systems store motherboard information in the PCI configuration space, which can be queried, but this is less common.
You can use INT 15h, AX=87h to get the PCI BIOS string, which may give a hint if the motherboard is managing PCI devices.
Example for querying PCI information:
#include <stdio.h>
#include <dos.h>
int main() {
union REGS regs;
char vendor[13];
// Call INT 15h, AX=87h to get PCI information
regs.x.ax = 0x8700;
int86(0x15, ®s, ®s);
// Return the PCI Vendor string from the DX register
*((unsigned int*)&vendor[0]) = regs.x.dx;
*((unsigned int*)&vendor[4]) = regs.x.bx;
*((unsigned int*)&vendor[8]) = regs.x.cx;
vendor[12] = '\0';
printf("PCI BIOS Vendor: %s\n", vendor);
return 0;
}
What You Can Get:
- PCI Vendor
- System Setup (CMOS)
Another source of system information is the CMOS (the small configuration memory used by the system). This is where settings like the system date, time, and boot configuration are stored. It’s often accessed via INT 1Ah for certain system configuration operations.
While CMOS doesn’t give direct motherboard info, it could provide clues about certain system features (like RAM size and CPU settings).
- Accessing DMI or SMBIOS Information
Unfortunately, DMI (Desktop Management Interface) and SMBIOS (System Management BIOS), which store detailed system information like motherboard type, BIOS version, manufacturer, etc., are not available in MS-DOS.
These interfaces are a modern feature typically used by Windows and other modern operating systems. They allow access to detailed hardware information, including the motherboard manufacturer, BIOS revision, CPU info, and more, but in MS-DOS, you cannot access this data directly.
- Limitations in MS-DOS
- BIOS
- Motherboard
- PCI BIOS
Summary
- BIOS Manufacturer and Version
- Motherboard Information
- PCI Devices
If you’re interested in more details about PCI devices or how to query other types of system information, feel free to ask!
You
What other potentially interesting things can I read out of my PC? let’s say I want to make some sort of diagnostics program.
So far I can find out the CPU, RAM, things from the BIOS. What about display info and attached storage devices?
ChatGPT
To create a diagnostics program in MS-DOS, you’re somewhat limited by the capabilities of real-mode interrupts and the available hardware abstraction layers. That being said, there are still a lot of interesting things you can query from your PC’s hardware. Below are some additional hardware details you can access, including display and storage information.
- Display Information
While you can’t directly query a lot of details about modern graphics hardware in MS-DOS, you can gather some basic information about the video mode and video memory.
Video Mode and Screen Resolution:
You can use INT 10h (Video BIOS interrupt) to query the current video mode, which tells you the resolution and color depth.
- INT 10h, AH=0x0F
- INT 10h, AH=0x0F
Example:
#include <stdio.h>
#include <dos.h>
int main() {
union REGS regs;
unsigned char video_mode;
// Get current video mode
regs.h.ah = 0x0F; // Get video mode
int86(0x10, ®s, ®s);
video_mode = regs.h.al; // AL contains the video mode number
printf("Current Video Mode: 0x%02X\n", video_mode);
// Depending on the mode, you can interpret resolution
if (video_mode == 0x13) {
printf("320x200, 256 colors (VGA mode)\n");
} else if (video_mode == 0x03) {
printf("80x25, 16 colors (Text mode)\n");
} else {
printf("Other mode\n");
}
return 0;
}
Video Memory:
You can inspect the amount of video memory using VGA memory in text mode or graphic mode. VGA typically uses 0xA000 to 0xAFFFF (64 KB) for graphics.
In graphics modes (such as mode 0x13), the video memory could be larger, and you can access the memory directly, but you’d need to map it correctly to handle it.
- 0xA000–0xAFFFF
- Video modes beyond this (like
- Storage Devices
While modern operating systems (like Windows or Linux) use advanced storage access methods like SATA, AHCI, or NVMe, MS-DOS uses INT 13h for basic disk operations. You can get information about attached storage devices (such as hard drives and floppy drives) using this interrupt.
Checking for Attached Drives (INT 13h)
Use INT 13h (disk services) to get disk drive parameters (such as the number of sectors, cylinders, heads) and disk type.
- INT 13h, AH=0x08
- INT 13h, AH=0x15
Here’s an example that queries drive parameters (you can check the drive’s type, size, and other info):
#include <stdio.h>
#include <dos.h>
int main() {
union REGS regs;
struct SREGS sregs;
regs.h.ah = 0x08; // Get drive parameters
regs.h.al = 0x80; // First hard drive (0x80 is typically the first hard disk)
int86x(0x13, ®s, ®s, &sregs);
if (regs.h.ah == 0) {
printf("Drive Parameters Retrieved!\n");
printf("Drive Type: 0x%02X\n", regs.h.al);
printf("Heads: %u\n", regs.x.bx);
printf("Cylinders: %u\n", regs.x.cx);
printf("Sectors per track: %u\n", regs.x.dx);
} else {
printf("Error retrieving drive parameters!\n");
}
return 0;
}
What You Can Retrieve with INT 13h:
- Drive Type
- Drive Parameters
- Disk Size
- Storage Information: Extended (Larger Hard Drives)
For modern large hard drives, INT 13h can be used, but extended BIOS services are needed for handling drives beyond the traditional 504MB limit. This is where INT 13h, AH=0x15 comes in, which is used to query extended information for large disks.
- INT 13h, AH=0x15
- Serial Ports and COM Devices
If you want to get information about serial ports or COM devices connected to the system, you can use the INT 14h (serial port BIOS interrupt). This can give you access to various settings of the serial communication ports.
- INT 14h
- INT 14h, AH=0x0F
Example:
#include <stdio.h>
#include <dos.h>
int main() {
union REGS regs;
regs.h.ah = 0x0F; // Get current configuration of COM ports
regs.h.al = 0x01; // COM1
int86(0x14, ®s, ®s);
printf("COM1 Port Status:\n");
printf("Port is %s\n", (regs.h.al & 0x01) ? "Open" : "Closed");
printf("Interrupt: 0x%02X\n", regs.h.bl); // Interrupt vector for the port
return 0;
}
- Network Adapters (via NDIS or other drivers)
In MS-DOS, network adapters (Ethernet cards, for example) usually require NDIS drivers to function. These drivers may provide their own methods for querying adapter information (like MAC addresses or configuration details). Unfortunately, querying detailed network interface information directly from BIOS or standard interrupts is not typically possible without the appropriate drivers being loaded.
You can try reading configuration files or using third-party drivers to fetch network-related diagnostics.
- System Timer and Performance Data
- INT 1Ah, AH=0x00
- Power Management Information
While MS-DOS doesn’t have advanced power management access, you could potentially infer some low-level information from the CMOS setup (e.g., battery status) by accessing the CMOS using INT 1Ah (System Configuration).
- Sound Devices
In MS-DOS, you would typically need to interact with specific sound card drivers (like Sound Blaster) to retrieve information about sound devices. Using interrupts like INT 22h may give you some access, but again, the exact information you’d want (like sound card details) depends on the specific driver in use.
Summary
Here’s what you can potentially query for a diagnostics program in MS-DOS:
- BIOS Information
- CPU
- RAM
- Display
- Storage
- Network Adapters
- Serial Ports
- Power/Performance
Let me know if you’d like to explore any of these topics in greater depth or need help with the code!