今天在網路瀏覽的時候看到SST 有提供 Software Driver 的範例程式,從範例程式中可以很容易的知道如何
去控制Flash part的存取 , 如果想學R/W Flash Part的朋友可以參考看看,而底下是一個範例程式:
SST25VF080B 8 Mbit(1M x 8) Serial Flash Memory
November 4th, 2005, Rev. 1.0
ABOUT THE SOFTWARE
This application note provides software driver examples for SST25VF080B,
Serial Flash. Extensive comments are included in each routine to describe
the function of each routine. The interface coding uses polling method
rather than the SPI protocol to interface with these serial devices. The
functions are differentiated below in terms of the communication protocols
(uses Mode 0) and specific device operation instructions. This code has been
designed to compile using the Keil compiler.
ABOUT THE SST25VF080B
Companion product datasheets for the SST25VF080B should be reviewed in
conjunction with this application note for a complete understanding
of the device.
Device Communication Protocol(pinout related) functions:
Functions Function
------------------------------------------------------------------
init Initializes clock to set up mode 0.
Send_Byte Sends one byte using SI pin to send and
shift out 1-bit per clock rising edge
Get_Byte Receives one byte using SO pin to receive and shift
in 1-bit per clock falling edge
Poll_SO Used in the polling for RY/BY# of SO during AAI programming
CE_High Sets Chip Enable pin of the serial flash to high
CE_Low Clears Chip Enable of the serial flash to low
Hold_Low Clears Hold pin to make serial flash hold
Unhold Unholds the serial flash
WP_Low Clears WP pin to make serial flash write protected
UnWP Disables write protection pin
Note: The pin names of the SST25VF080B are used in this application note. The associated test code
will not compile unless these pinouts (SCK, SI, SO, SO, CE, WP, Hold) are pre-defined on your
software which should reflect your hardware interfaced.
Device Operation Instruction functions:
Functions Function
------------------------------------------------------------------
Read_Status_Register Reads the status register of the serial flash
EWSR Enables the Write Status Register
WRSR Performs a write to the status register
WREN Write enables the serial flash
WRDI Write disables the serial flash
EBSY Enable SO to output RY/BY# status during AAI programming
DBSY Disable SO to output RY/BY# status during AAI programming
Read_ID Reads the manufacturer ID and device ID
Jedec_ID_Read Reads the Jedec ID
Read Reads one byte from the serial flash and returns byte(max of 25 MHz CLK frequency)
Read_Cont Reads multiple bytes(max of 25 MHz CLK frequency)
HighSpeed_Read Reads one byte from the serial flash and returns byte(max of 50 MHz CLK frequency)
HighSpeed_Read_Cont Reads multiple bytes(max of 50 MHz CLK frequency)
Byte_Program Program one byte to the serial flash
Auto_Add_IncA Initial Auto Address Increment process
Auto_Add_IncB Successive Auto_Address_Increment process after AAI initiation
Auto_Add_IncA_EBSY Initial Auto Address Increment process with EBSY
Auto_Add_IncB_EBSY Successive Auto_Address_Increment process after AAI initiation with EBSY and WRDI/DBSY
Chip_Erase Erases entire serial flash
Sector_Erase Erases one sector (4 KB) of the serial flash
Block_Erase_32K Erases 32 KByte block memory of the serial flash
Block_Erase_64K Erases 64 KByte block memory of the serial flash
Wait_Busy Polls status register until busy bit is low
Wait_Busy_AAI Polls status register until busy bit is low for AAI programming
WREN_Check Checks to see if WEL is set
WREN_AAI_Check Checks to see if WEL and AAI mode is set
"C" LANGUAGE DRIVERS
/********************************************************************/
/* Copyright Silicon Storage Technology, Inc. (SST), 1994-2005 */
/* Example "C" language Driver of SST25VF080B Serial Flash */
/* Conrado Canio, Silicon Storage Technology, Inc. */
/* */
/* Revision 1.0, November 4th, 2005 */
/* */
/* */
/********************************************************************/
#include
#include
/* Function Prototypes */
void init();
void Send_Byte(unsigned char out);
unsigned char Get_Byte();
void Poll_SO();
void CE_High();
void CE_Low();
void Hold_Low();
void Unhold();
void WP_Low();
void UnWP();
unsigned char Read_Status_Register();
void EWSR();
void WRSR(byte);
void WREN();
void WRDI();
void EBSY();
void DBSY();
unsigned char Read_ID(ID_addr);
unsigned long Jedec_ID_Read();
unsigned char Read(unsigned long Dst);
void Read_Cont(unsigned long Dst, unsigned long no_bytes);
unsigned char HighSpeed_Read(unsigned long Dst);
void HighSpeed_Read_Cont(unsigned long Dst, unsigned long no_bytes);
void Byte_Program(unsigned long Dst, unsigned char byte);
void Auto_Add_IncA(unsigned long Dst, unsigned char byte1, unsigned char byte2);
void Auto_Add_IncB(unsigned char byte1, unsigned char byte2);
void Auto_Add_IncA_EBSY(unsigned long Dst, unsigned char byte1, unsigned char byte2);
void Auto_Add_IncB_EBSY(unsigned char byte1, unsigned char byte2);
void Chip_Erase();
void Sector_Erase(unsigned long Dst);
void Block_Erase_32K(unsigned long Dst);
void Block_Erase_64K(unsigned long Dst);
void Wait_Busy();
void Wait_Busy_AAI();
void WREN_Check();
void WREN_AAI_Check();
void Verify(unsigned char byte, unsigned char cor_byte);
unsigned char idata upper_128[128]; /* global array to store read data */
/* to upper RAM area from 80H - FFH */
/************************************************************************/
/* PROCEDURE: init */
/* */
/* This procedure initializes the SCK to low. Must be called prior to */
/* setting up mode 0. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* SCK */
/************************************************************************/
void init()
{
SCK = 0; /* set clock to low initial state */
}
/************************************************************************/
/* PROCEDURE: Send_Byte */
/* */
/* This procedure outputs a byte shifting out 1-bit per clock rising */
/* edge on the the SI pin(LSB 1st). */
/* */
/* Input: */
/* out */
/* */
/* Output: */
/* SI */
/************************************************************************/
void Send_Byte(unsigned char out)
{
unsigned char i = 0;
for (i = 0; i < 8; i++)
{
if ((out & 0x80) == 0x80) /* check if MSB is high */
SI = 1;
else
SI = 0; /* if not, set to low */
SCK = 1; /* toggle clock high */
out = (out << 1); /* shift 1 place for next bit */
SCK = 0; /* toggle clock low */
}
}
/************************************************************************/
/* PROCEDURE: Get_Byte */
/* */
/* This procedure inputs a byte shifting in 1-bit per clock falling */
/* edge on the SO pin(LSB 1st). */
/* */
/* Input: */
/* SO */
/* */
/* Output: */
/* None */
/************************************************************************/
unsigned char Get_Byte()
{
unsigned char i = 0, in = 0, temp = 0;
for (i = 0; i < 8; i++)
{
in = (in << 1); /* shift 1 place to the left or shift in 0 */
temp = SO; /* save input */
SCK = 1; /* toggle clock high */
if (temp == 1) /* check to see if bit is high */
in = in | 0x01; /* if high, make bit high */
SCK = 0; /* toggle clock low */
}
return in;
}
/************************************************************************/
/* PROCEDURE: Poll_SO */
/* */
/* This procedure polls for the SO line during AAI programming */
/* waiting for SO to transition to 1 which will indicate AAI programming*/
/* is completed */
/* */
/* Input: */
/* SO */
/* */
/* Output: */
/* None */
/************************************************************************/
void Poll_SO()
{
unsigned char temp = 0;
CE_Low();
while (temp == 0x00) /* waste time until not busy */
temp = SO;
CE_High();
}
/************************************************************************/
/* PROCEDURE: CE_High */
/* */
/* This procedure set CE = High. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* CE */
/* */
/************************************************************************/
void CE_High()
{
CE = 1; /* set CE high */
}
/************************************************************************/
/* PROCEDURE: CE_Low */
/* */
/* This procedure drives the CE of the device to low. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* CE */
/* */
/************************************************************************/
void CE_Low()
{
CE = 0; /* clear CE low */
}
/************************************************************************/
/* PROCEDURE: Hold() */
/* */
/* This procedure clears the Hold pin to low. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* Hold */
/************************************************************************/
void Hold_Low()
{
Hold = 0; /* clear Hold pin */
}
/************************************************************************/
/* PROCEDURE: Unhold() */
/* */
/* This procedure sets the Hold pin to high. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* Hold */
/************************************************************************/
void Unhold()
{
Hold = 1; /* set Hold pin */
}
/************************************************************************/
/* PROCEDURE: WP() */
/* */
/* This procedure clears the WP pin to low. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* WP */
/************************************************************************/
void WP_Low()
{
WP = 0; /* clear WP pin */
}
/************************************************************************/
/* PROCEDURE: UnWP() */
/* */
/* This procedure sets the WP pin to high. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* WP */
/************************************************************************/
void UnWP()
{
WP = 1; /* set WP pin */
}
/************************************************************************/
/* PROCEDURE: Read_Status_Register */
/* */
/* This procedure read the status register and returns the byte. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* byte */
/************************************************************************/
unsigned char Read_Status_Register()
{
unsigned char byte = 0;
CE_Low(); /* enable device */
Send_Byte(0x05); /* send RDSR command */
byte = Get_Byte(); /* receive byte */
CE_High(); /* disable device */
return byte;
}
/************************************************************************/
/* PROCEDURE: EWSR */
/* */
/* This procedure Enables Write Status Register. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void EWSR()
{
CE_Low(); /* enable device */
Send_Byte(0x50); /* enable writing to the status register */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: WRSR */
/* */
/* This procedure writes a byte to the Status Register. */
/* */
/* Input: */
/* byte */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WRSR(byte)
{
CE_Low(); /* enable device */
Send_Byte(0x01); /* select write to status register */
Send_Byte(byte); /* data that will change the status of BPx
or BPL (only bits 2,3,4,5,7 can be written) */
CE_High(); /* disable the device */
}
/************************************************************************/
/* PROCEDURE: WREN */
/* */
/* This procedure enables the Write Enable Latch. It can also be used */
/* to Enables Write Status Register. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WREN()
{
CE_Low(); /* enable device */
Send_Byte(0x06); /* send WREN command */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: WRDI */
/* */
/* This procedure disables the Write Enable Latch. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WRDI()
{
CE_Low(); /* enable device */
Send_Byte(0x04); /* send WRDI command */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: EBSY */
/* */
/* This procedure enable SO to output RY/BY# status during AAI */
/* programming. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void EBSY()
{
CE_Low(); /* enable device */
Send_Byte(0x70); /* send EBSY command */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: DBSY */
/* */
/* This procedure disable SO as output RY/BY# status signal during AAI */
/* programming. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void DBSY()
{
CE_Low(); /* enable device */
Send_Byte(0x80); /* send DBSY command */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Read_ID */
/* */
/* This procedure Reads the manufacturer's ID and device ID. It will */
/* use 90h or ABh as the command to read the ID (90h in this sample). */
/* It is up to the user to give the last byte ID_addr to determine */
/* whether the device outputs manufacturer's ID first, or device ID */
/* first. Please see the product datasheet for details. Returns ID in */
/* variable byte. */
/* */
/* Input: */
/* ID_addr */
/* */
/* Returns: */
/* byte: ID1(Manufacture's ID = BFh or Device ID = 8Eh) */
/* */
/************************************************************************/
unsigned char Read_ID(ID_addr)
{
unsigned char byte;
CE_Low(); /* enable device */
Send_Byte(0x90); /* send read ID command (90h or ABh) */
Send_Byte(0x00); /* send address */
Send_Byte(0x00); /* send address */
Send_Byte(ID_addr); /* send address - either 00H or 01H */
byte = Get_Byte(); /* receive byte */
CE_High(); /* disable device */
return byte;
}
/************************************************************************/
/* PROCEDURE: Jedec_ID_Read */
/* */
/* This procedure Reads the manufacturer's ID (BFh), memory type (25h) */
/* and device ID (8Eh). It will use 9Fh as the JEDEC ID command. */
/* Please see the product datasheet for details. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* IDs_Read:ID1(Manufacture's ID = BFh, Memory Type (25h), */
/* and Device ID (8Eh) */
/* */
/************************************************************************/
unsigned long Jedec_ID_Read()
{
unsigned long temp;
temp = 0;
CE_Low(); /* enable device */
Send_Byte(0x9F); /* send JEDEC ID command (9Fh) */
temp = (temp | Get_Byte()) << 8; /* receive byte */
temp = (temp | Get_Byte()) << 8;
temp = (temp | Get_Byte()); /* temp value = 0xBF258E */
CE_High(); /* disable device */
return temp;
}
/************************************************************************/
/* PROCEDURE: Read */
/* */
/* This procedure reads one address of the device. It will return the */
/* byte read in variable byte. */
/* */
/* */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* */
/* Returns: */
/* byte */
/* */
/************************************************************************/
unsigned char Read(unsigned long Dst)
{
unsigned char byte = 0;
CE_Low(); /* enable device */
Send_Byte(0x03); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
byte = Get_Byte();
CE_High(); /* disable device */
return byte; /* return one byte read */
}
/************************************************************************/
/* PROCEDURE: Read_Cont */
/* */
/* This procedure reads multiple addresses of the device and stores */
/* data into 128 byte buffer. Maximum byte that can be read is 128 bytes*/
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* no_bytes Number of bytes to read (max = 128) */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Read_Cont(unsigned long Dst, unsigned long no_bytes)
{
unsigned long i = 0;
CE_Low(); /* enable device */
Send_Byte(0x03); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
for (i = 0; i < no_bytes; i++) /* read until no_bytes is reached */
{
upper_128[i] = Get_Byte(); /* receive byte and store at address 80H - FFH */
}
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: HighSpeed_Read */
/* */
/* This procedure reads one address of the device. It will return the */
/* byte read in variable byte. */
/* */
/* */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* */
/* Returns: */
/* byte */
/* */
/************************************************************************/
unsigned char HighSpeed_Read(unsigned long Dst)
{
unsigned char byte = 0;
CE_Low(); /* enable device */
Send_Byte(0x0B); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(0xFF); /*dummy byte*/
byte = Get_Byte();
CE_High(); /* disable device */
return byte; /* return one byte read */
}
/************************************************************************/
/* PROCEDURE: HighSpeed_Read_Cont */
/* */
/* This procedure reads multiple addresses of the device and stores */
/* data into 128 byte buffer. Maximum byte that can be read is 128 bytes*/
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* no_bytes Number of bytes to read (max = 128) */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void HighSpeed_Read_Cont(unsigned long Dst, unsigned long no_bytes)
{
unsigned long i = 0;
CE_Low(); /* enable device */
Send_Byte(0x0B); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(0xFF); /*dummy byte*/
for (i = 0; i < no_bytes; i++) /* read until no_bytes is reached */
{
upper_128[i] = Get_Byte(); /* receive byte and store at address 80H - FFH */
}
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Byte_Program */
/* */
/* This procedure programs one address of the device. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* byte: byte to be programmed */
/* */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Byte_Program(unsigned long Dst, unsigned char byte)
{
CE_Low(); /* enable device */
Send_Byte(0x02); /* send Byte Program command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(byte); /* send byte to be programmed */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Auto_Add_IncA */
/* */
/* This procedure programs consecutive addresses of 2 bytes of data into*/
/* the device: 1st data byte will be programmed into the initial */
/* address [A23-A1] and with A0 = 0. The 2nd data byte will be be */
/* programmed into initial address [A23-A1] and with A0 = 1. This */
/* is used to to start the AAI process. It should be followed by */
/* Auto_Add_IncB. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* */
/* Note: Only RDSR command can be executed once in AAI mode with SO */
/* disable to output RY/BY# status. Use WRDI to exit AAI mode */
/* unless AAI is programming the last address or last address of */
/* unprotected block, which automatically exits AAI mode. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* byte1: 1st byte to be programmed */
/* byte1: 2nd byte to be programmed */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncA(unsigned long Dst, unsigned char byte1, unsigned char byte2)
{
CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Auto_Add_IncB */
/* */
/* This procedure programs consecutive addresses of 2 bytes of data into*/
/* the device: 1st data byte will be programmed into the initial */
/* address [A23-A1] and with A0 = 0. The 2nd data byte will be be */
/* programmed into initial address [A23-A1] and with A0 = 1. This */
/* is used after Auto_Address_IncA. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* Note: Only WRDI and AAI command can be executed once in AAI mode */
/* with SO enabled as RY/BY# status. When the device is busy */
/* asserting CE# will output the status of RY/BY# on SO. Use WRDI */
/* to exit AAI mode unless AAI is programming the last address or */
/* last address of unprotected block, which automatically exits */
/* AAI mode. */
/* */
/* Input: */
/* */
/* byte1: 1st byte to be programmed */
/* byte2: 2nd byte to be programmed */
/* */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncB(unsigned char byte1, unsigned char byte2)
{
CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Auto_Add_IncA_EBSY */
/* */
/* This procedure is the same as procedure Auto_Add_IncA except that it */
/* uses EBSY and Poll_SO functions to check for RY/BY. It programs */
/* consecutive addresses of the device. The 1st data byte will be */
/* programmed into the initial address [A23-A1] and with A0 = 0. The */
/* 2nd data byte will be programmed into initial address [A23-A1] and */
/* with A0 = 1. This is used to to start the AAI process. It should */
/* be followed by Auto_Add_IncB_EBSY. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* */
/* Note: Only WRDI and AAI command can be executed once in AAI mode */
/* with SO enabled as RY/BY# status. When the device is busy */
/* asserting CE# will output the status of RY/BY# on SO. Use WRDI */
/* to exit AAI mode unless AAI is programming the last address or */
/* last address of unprotected block, which automatically exits */
/* AAI mode. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* byte1: 1st byte to be programmed */
/* byte1: 2nd byte to be programmed */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncA_EBSY(unsigned long Dst, unsigned char byte1, unsigned char byte2)
{
EBSY(); /* enable RY/BY# status for SO in AAI */
CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */
Poll_SO(); /* polls RY/BY# using SO line */
}
/************************************************************************/
/* PROCEDURE: Auto_Add_IncB_EBSY */
/* */
/* This procedure is the same as Auto_Add_IncB except that it uses */
/* Poll_SO to poll for RY/BY#. It demonstrate on how to use DBSY after */
/* AAI programmming is completed. It programs consecutive addresses of */
/* the device. The 1st data byte will be programmed into the initial */
/* address [A23-A1] and with A0 = 0. The 2nd data byte will be */
/* programmed into initial address [A23-A1] and with A0 = 1. This is */
/* used after Auto_Address_IncA. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* Note: Only WRDI and AAI command can be executed once in AAI mode */
/* with SO enabled as RY/BY# status. When the device is busy, */
/* asserting CE# will output the status of RY/BY# on SO. Use WRDI */
/* to exit AAI mode unless AAI is programming the last address or */
/* last address of unprotected block, which automatically exits */
/* AAI mode. */
/* */
/* Input: */
/* */
/* byte1: 1st byte to be programmed */
/* byte2: 2nd byte to be programmed */
/* */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncB_EBSY(unsigned char byte1, unsigned char byte2)
{
CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */
Poll_SO(); /* polls RY/BY# using SO line */
WRDI(); /* Exit AAI before executing DBSY */
DBSY(); /* disable SO as RY/BY# output if in AAI */
}
/************************************************************************/
/* PROCEDURE: Chip_Erase */
/* */
/* This procedure erases the entire Chip. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Chip_Erase()
{
CE_Low(); /* enable device */
Send_Byte(0x60); /* send Chip Erase command (60h or C7h) */
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Sector_Erase */
/* */
/* This procedure Sector Erases the Chip. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Sector_Erase(unsigned long Dst)
{
CE_Low(); /* enable device */
Send_Byte(0x20); /* send Sector Erase command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Block_Erase_32K */
/* */
/* This procedure Block Erases 32 KByte of the Chip. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Block_Erase_32K(unsigned long Dst)
{
CE_Low(); /* enable device */
Send_Byte(0x52); /* send 32 KByte Block Erase command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Block_Erase_64K */
/* */
/* This procedure Block Erases 64 KByte of the Chip. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Block_Erase_64K(unsigned long Dst)
{
CE_Low(); /* enable device */
Send_Byte(0xD8); /* send 64KByte Block Erase command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
CE_High(); /* disable device */
}
/************************************************************************/
/* PROCEDURE: Wait_Busy */
/* */
/* This procedure waits until device is no longer busy (can be used by */
/* Byte-Program, Sector-Erase, Block-Erase, Chip-Erase). */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Wait_Busy()
{
while (Read_Status_Register() == 0x03) /* waste time until not busy */
Read_Status_Register();
}
/************************************************************************/
/* PROCEDURE: Wait_Busy_AAI */
/* */
/* This procedure waits until device is no longer busy for AAI mode. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Wait_Busy_AAI()
{
while (Read_Status_Register() == 0x43) /* waste time until not busy */
Read_Status_Register();
}
/************************************************************************/
/* PROCEDURE: WREN_Check */
/* */
/* This procedure checks to see if WEL bit set before program/erase. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WREN_Check()
{
unsigned char byte;
byte = Read_Status_Register(); /* read the status register */
if (byte != 0x02) /* verify that WEL bit is set */
{
while(1)
/* add source code or statements for this file */
/* to compile */
/* i.e. option: insert a display to view error on LED? */
}
}
/************************************************************************/
/* PROCEDURE: WREN_AAI_Check */
/* */
/* This procedure checks for AAI and WEL bit once in AAI mode. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WREN_AAI_Check()
{
unsigned char byte;
byte = Read_Status_Register(); /* read the status register */
if (byte != 0x42) /* verify that AAI and WEL bit is set */
{
while(1)
/* add source code or statements for this file */
/* to compile */
/* i.e. option: insert a display to view error on LED? */
}
}
/************************************************************************/
/* PROCEDURE: Verify */
/* */
/* This procedure checks to see if the correct byte has be read. */
/* */
/* Input: */
/* byte: byte read */
/* cor_byte: correct_byte that should be read */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Verify(unsigned char byte, unsigned char cor_byte)
{
if (byte != cor_byte)
{
while(1)
/* add source code or statement for this file */
/* to compile */
/* i.e. option: insert a display to view error on LED? */
}
}
int main()
{
return 0;
}
而範例程式中已經把主要的控制方式的"概念"都已經列出來了!
所以只要讀一下Datasheet應該就可以了解他的意義!
至於main()裡面要做甚麼就因人而異,因此千萬不要問我 main()要怎麼寫!
Reference
http://www.sst.com
點Software Driver 旁邊的TXT就可以看到範例程式
將自己踏入BIOS領域中所學習到的知識做一些心得整理,像是Legacy BIOS、EFI BIOS、Windows Driver...etc. ※版權與智慧財產權聲明:保留所有法律權利。我在寫文章時如果有引用到其他人的地方我會盡量說明參考出處,如果有遺漏的地方請告訴我,我會馬上註明! 而轉貼我的文章時也請您註明出處!
星期二, 12月 23, 2008
SST SPI Serial Flash
星期六, 12月 13, 2008
網友Joey的網站
今天收到一位網友Joey的來信,來信中分享了他的網站以及他的作品!
在瀏覽過他的網站與作品後,看到他對自己的作品有所堅持並且加入自己的巧思與創新,然後開發出不一樣感覺的工具! 真是深深的佩服他!
看到他這麼努力的研究,就更感覺自己太懶惰了! 以前為了寫程式廢寢忘食的我去了哪裡呢?!
我自己也要反省一下了>.<... 以下是他的作品之一的簡介,如果有興趣的朋友可以去他的網站下載:
Mini OSW 是全世界最小的多重開機程式,只有 396 Bytes,
如果你原本有使用其它的多重開機程式,
也可以很快的使用 MiniOSW 替代。
可說是,麻雀雖小,五臟俱全。
Joey 的網站:
http://chizone.miroko.tw/
在瀏覽過他的網站與作品後,看到他對自己的作品有所堅持並且加入自己的巧思與創新,然後開發出不一樣感覺的工具! 真是深深的佩服他!
看到他這麼努力的研究,就更感覺自己太懶惰了! 以前為了寫程式廢寢忘食的我去了哪裡呢?!
我自己也要反省一下了>.<... 以下是他的作品之一的簡介,如果有興趣的朋友可以去他的網站下載:
Mini OSW 是全世界最小的多重開機程式,只有 396 Bytes,
如果你原本有使用其它的多重開機程式,
也可以很快的使用 MiniOSW 替代。
可說是,麻雀雖小,五臟俱全。
Joey 的網站:
http://chizone.miroko.tw/
星期日, 12月 07, 2008
MRT v.s Microsoft® Windows® 惡意軟體移除工具
MRT ?? 不是指我們的捷運 Metropolitan Rapid Transit(M.R.T 大都會捷運系統)!
一般如果你有安裝正版的Vista 或是XP , 而且有開啟自動更新功能時,你會發現他會自動下載一個叫做Microsoft® Windows® 惡意軟體移除工具的軟體! 當他安裝好之後你卻不曾看過他執行!
要如何使用微軟提供的這的工具呢?
很簡單,你只要到 開始->執行 ,然後鍵入"MRT"後按下確定,那麼這個工具就會被你叫出來執行了!
一般如果你有安裝正版的Vista 或是XP , 而且有開啟自動更新功能時,你會發現他會自動下載一個叫做Microsoft® Windows® 惡意軟體移除工具的軟體! 當他安裝好之後你卻不曾看過他執行!
要如何使用微軟提供的這的工具呢?
很簡單,你只要到 開始->執行 ,然後鍵入"MRT"後按下確定,那麼這個工具就會被你叫出來執行了!
星期一, 11月 03, 2008
VS2005 Debugger
最近在學習使用VS2005環境,慢慢熟悉一些介面以及開啟專案...etc.
而這個過程中遇到了一個很基本的問題,害我突然腦袋空白了一陣子.....>.< 這個問題是在Debugger 一個程式碼的時候遇到的... 一般我們C語言中的進入點假設寫成這樣: int main ( int Argc, INT8 *Argv[] ) 我很直覺就是按下F5 開始Debugger ...但是今天突然間要在command line 放一些引數後再讓我的Debugger可以開始Trace code... 於是我腦袋突然空白了...VS2005 要在哪邊設定 ...冏 我在Debugger的Code是EFI的ProcessDSC , 因為平常都是在MakeFile設定,command line , 所以要拿來用Debuuger追code 還真的讓我不知所措了一陣子. 不過後來找到了VS2005設定的地方,也順利的可以繼續往下追了! 這個問題也就解決了! 這邊就把我找到的設定地方做個筆記,方便自己以後可以查閱! 下圖是VS2005 --> Property Page --> Configuration Properties --> Debuggung 的設定
只要在Command Arguments 填入要設定的引數,然後按下F5時就可以帶進去了!
下圖是Debugger中下斷點時可以看到Argv[1]是我設定的引數:
而這個過程中遇到了一個很基本的問題,害我突然腦袋空白了一陣子.....>.< 這個問題是在Debugger 一個程式碼的時候遇到的... 一般我們C語言中的進入點假設寫成這樣: int main ( int Argc, INT8 *Argv[] ) 我很直覺就是按下F5 開始Debugger ...但是今天突然間要在command line 放一些引數後再讓我的Debugger可以開始Trace code... 於是我腦袋突然空白了...VS2005 要在哪邊設定 ...冏 我在Debugger的Code是EFI的ProcessDSC , 因為平常都是在MakeFile設定,command line , 所以要拿來用Debuuger追code 還真的讓我不知所措了一陣子. 不過後來找到了VS2005設定的地方,也順利的可以繼續往下追了! 這個問題也就解決了! 這邊就把我找到的設定地方做個筆記,方便自己以後可以查閱! 下圖是VS2005 --> Property Page --> Configuration Properties --> Debuggung 的設定
只要在Command Arguments 填入要設定的引數,然後按下F5時就可以帶進去了!
標籤:
Windows 程式相關
星期一, 10月 06, 2008
ACPIView for both vista and XP
感謝網友nickel授權,我把ACPI view 放在我的部落格給有需要的人下載!
這個版本只能列舉,所以功能有些限制,如果需要更多資訊的人請聯絡nickel,,他應該會給大家更仔細的說明!
點我下載ACPIView for both vista&XP
這個版本只能列舉,所以功能有些限制,如果需要更多資訊的人請聯絡nickel,,他應該會給大家更仔細的說明!
點我下載ACPIView for both vista&XP
星期二, 9月 30, 2008
JR! Sean Kingston! Beautiful girl
最近請小洋開車幫我搬家,在他車上聽到這首歌,感覺還不錯所以就去找了歌詞回來聽~
因為還不錯聽,所以就順便把歌詞放在Blog分享一下~~~
【JR! Sean Kingston! Beautiful girl】
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal
你在令我走向毀滅 毀滅
When you say it’s over
當你說我們緣分到此為至
Damn all these beautiful girls
這些可恨的美女
They only wanna do your dirt
她們只想挑出妳的是是非非
They'll have you suicidal, suicidal
她們也想讓你走向毀滅 毀滅
When they say it’s over
當她們說一切結束了
See it started at the park
記得我們那是在一個公園的黃昏
Used to chill at the dark
當時的晚風有些冷凜
Oh when you took my heart
哦 當你帶走了我的心
That's when we fell apart
我們迷失了自己
Coz we both thought
因為我們都認為
That love lasts forever (lasts forever)
愛會永恆(永恆)
They say we're too young
人們都說我們太過年輕
To get ourselves sprung
太易衝動
Oh we didn't care
哦 我們不曾在乎
We made it very clear
我們也都明瞭清楚
And they also said
他們甚至說
That we couldn't last together (last together)
說我們不會長久(長久)
See it's very define, girl
女孩 這不用置疑
One of a kind
你是那樣的無與倫比
But you mush up my mind
而你讓我意亂情迷
You walk to get declined
卻讓我們的愛衰逝
Oh Lord…
哦 老天
My baby is driving me crazy
你真的讓令我發瘋發癲
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal
你在令我走向毀滅 毀滅
When you say it's over
當你說我們緣分到此為至
Damn all these beautiful girls
這些可恨的美女
They only wanna do your dirt
她們只想挑出妳的是是非非
They'll have you suicidal, suicidal
她們也想讓你走向毀滅 毀滅
When they say it's over
當她們說一切結束了
It was back in '99
回想九九的那一年
Watchin' movies all the time
除了看電影整日無所事事
Oh when I went away
哦 那時我還懵懂
For doin' my first crime
還做些偷雞摸狗的混事
And I never thought
但我從沒想過
That we was gonna see each other (see each other)
那天的碰面你我會一見鍾情(一見鍾情)
And then I came out
於是我混沌初開
Mami moved me down South
媽咪雖帶我去了南方
Oh I'm with my girl
哦 可我卻整日想著我的女孩
Who I thought was my world
因為我以為她就是我的世界
It came out to be
可結果是
That she wasn't the girl for me (girl for me)
她卻離我而去(而去)
See it's very define, girl
女孩 這不用置疑
One of a kind
你是那樣的無與倫比
But you mush up my mind
而你讓我意亂情迷
You walk to get declined
卻讓我們的愛衰逝
Oh Lord…
哦 老天
My baby is driving me crazy
你真的讓令我發瘋發癲
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal
你在令我走向毀滅 毀滅
When you say it’s over
當你說我們緣分到此為至
Damn all these beautiful girls
這些可恨的美女
They only wanna do your dirt
她們只想挑出妳的是是非非
They’ll have you suicidal, suicidal
她們也想讓你走向毀滅 毀滅
When they say it's over
當她們說一切結束了
Now we're fussin’
現在我們的焦躁
And now we're fightin’
我們在掙扎
Please tell me why
請告訴我為什麼
I'm feelin' slightin'
我是那樣的無望
And I don't know
我不知道
How to make it better (make it better)
該怎麼來彌補(彌補)
You're datin' other guys
你想著其他男人
You're tellin' me lies
還對我謊話連篇
Oh I can't believe
哦 我不敢相信
What I'm seein' with my eyes
可我親眼所見
I'm losin' my mind
從此迷失心智
And I don't think it's clever (think it's clever)
雖然我知道這並不明智(並不明智)
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal, suicidal
你在令我走向毀滅 毀滅 毀滅 ....
因為還不錯聽,所以就順便把歌詞放在Blog分享一下~~~
【JR! Sean Kingston! Beautiful girl】
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal
你在令我走向毀滅 毀滅
When you say it’s over
當你說我們緣分到此為至
Damn all these beautiful girls
這些可恨的美女
They only wanna do your dirt
她們只想挑出妳的是是非非
They'll have you suicidal, suicidal
她們也想讓你走向毀滅 毀滅
When they say it’s over
當她們說一切結束了
See it started at the park
記得我們那是在一個公園的黃昏
Used to chill at the dark
當時的晚風有些冷凜
Oh when you took my heart
哦 當你帶走了我的心
That's when we fell apart
我們迷失了自己
Coz we both thought
因為我們都認為
That love lasts forever (lasts forever)
愛會永恆(永恆)
They say we're too young
人們都說我們太過年輕
To get ourselves sprung
太易衝動
Oh we didn't care
哦 我們不曾在乎
We made it very clear
我們也都明瞭清楚
And they also said
他們甚至說
That we couldn't last together (last together)
說我們不會長久(長久)
See it's very define, girl
女孩 這不用置疑
One of a kind
你是那樣的無與倫比
But you mush up my mind
而你讓我意亂情迷
You walk to get declined
卻讓我們的愛衰逝
Oh Lord…
哦 老天
My baby is driving me crazy
你真的讓令我發瘋發癲
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal
你在令我走向毀滅 毀滅
When you say it's over
當你說我們緣分到此為至
Damn all these beautiful girls
這些可恨的美女
They only wanna do your dirt
她們只想挑出妳的是是非非
They'll have you suicidal, suicidal
她們也想讓你走向毀滅 毀滅
When they say it's over
當她們說一切結束了
It was back in '99
回想九九的那一年
Watchin' movies all the time
除了看電影整日無所事事
Oh when I went away
哦 那時我還懵懂
For doin' my first crime
還做些偷雞摸狗的混事
And I never thought
但我從沒想過
That we was gonna see each other (see each other)
那天的碰面你我會一見鍾情(一見鍾情)
And then I came out
於是我混沌初開
Mami moved me down South
媽咪雖帶我去了南方
Oh I'm with my girl
哦 可我卻整日想著我的女孩
Who I thought was my world
因為我以為她就是我的世界
It came out to be
可結果是
That she wasn't the girl for me (girl for me)
她卻離我而去(而去)
See it's very define, girl
女孩 這不用置疑
One of a kind
你是那樣的無與倫比
But you mush up my mind
而你讓我意亂情迷
You walk to get declined
卻讓我們的愛衰逝
Oh Lord…
哦 老天
My baby is driving me crazy
你真的讓令我發瘋發癲
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal
你在令我走向毀滅 毀滅
When you say it’s over
當你說我們緣分到此為至
Damn all these beautiful girls
這些可恨的美女
They only wanna do your dirt
她們只想挑出妳的是是非非
They’ll have you suicidal, suicidal
她們也想讓你走向毀滅 毀滅
When they say it's over
當她們說一切結束了
Now we're fussin’
現在我們的焦躁
And now we're fightin’
我們在掙扎
Please tell me why
請告訴我為什麼
I'm feelin' slightin'
我是那樣的無望
And I don't know
我不知道
How to make it better (make it better)
該怎麼來彌補(彌補)
You're datin' other guys
你想著其他男人
You're tellin' me lies
還對我謊話連篇
Oh I can't believe
哦 我不敢相信
What I'm seein' with my eyes
可我親眼所見
I'm losin' my mind
從此迷失心智
And I don't think it's clever (think it's clever)
雖然我知道這並不明智(並不明智)
You're way too beautiful girl
女孩,妳過於的完美
That's why it'll never work
這就是為何我們的愛情始終沒有結局
You'll have me suicidal, suicidal, suicidal
你在令我走向毀滅 毀滅 毀滅 ....
星期三, 9月 10, 2008
BIOS 輔助工具
很多朋友在問我, BIOS工程師一般都會拿哪些工具去輔助?!
這邊我就列出幾個比較看到的工具給大家參考一下:
DOS
● RU.EXE - AMI 公司的一個工具,可以在dos下查看硬體資訊, 從原作者網站得到的資訊如下:
1. PCI configuration space
2. PCI Express
3. Super I/O chipsets
4. System chipsets
5. 16bit port read/write up to 32bit data
6. IO space
7. IDE data returned by Identify Command
8. Up to 4GB memory read/write (In EMM386/Windows 9x max=1MB)
9. CPU MSRs
10. SMBIOS data
11. SMBUS data
●Debug.com - DOS自帶的工具,可以簡易的輔助你反組譯程式碼
●Debug32.exe - Quantasm Corp. 出版的工具,同Debug.com但是可以查看 32 bit Register.
Windows
●SE.EXE - 同RU.EXE功能,Windows版本!
●RW-Everything - 同SE.EXE 視窗版,之前PCIE BaseAddr會讀取錯誤現在不知道改好了沒?!
●AcpiView - Microsoft for Windows 2000/XP ,可查看ACPI Table
●AcpiViewVista - 網友nickel 寫的,同AcpiView 可在Vista下查看ACPI Table
●ACPIScope - 同ACPI view功能,可查看ACPI Table
●DMIScope - 可查看DMI Table
●PCIScope - 可查看PCI/PCIE Info
●Key101.exe - 我T學長的以前同事key寫的(目前人還在我們公司某NB單位),功能同SE.EXE 但針對P公司BIOS撰寫!所以可讀取一些BIOS資訊!
●USBView.exe - 可列舉USB 設備在哪些Controller上.
以上工具的介紹可在下面網站下載或是得到相關資訊,至於相關版權問題請自行與作者洽詢!
Reference
http://ruexe.blogspot.com/
http://rweverything.phpnet.us/
http://www.tssc.de/index.htm
http://www.programmer-club.com
這邊我就列出幾個比較看到的工具給大家參考一下:
DOS
● RU.EXE - AMI 公司的一個工具,可以在dos下查看硬體資訊, 從原作者網站得到的資訊如下:
1. PCI configuration space
2. PCI Express
3. Super I/O chipsets
4. System chipsets
5. 16bit port read/write up to 32bit data
6. IO space
7. IDE data returned by Identify Command
8. Up to 4GB memory read/write (In EMM386/Windows 9x max=1MB)
9. CPU MSRs
10. SMBIOS data
11. SMBUS data
●Debug.com - DOS自帶的工具,可以簡易的輔助你反組譯程式碼
●Debug32.exe - Quantasm Corp. 出版的工具,同Debug.com但是可以查看 32 bit Register.
Windows
●SE.EXE - 同RU.EXE功能,Windows版本!
●RW-Everything - 同SE.EXE 視窗版,之前PCIE BaseAddr會讀取錯誤現在不知道改好了沒?!
●AcpiView - Microsoft for Windows 2000/XP ,可查看ACPI Table
●AcpiViewVista - 網友nickel 寫的,同AcpiView 可在Vista下查看ACPI Table
●ACPIScope - 同ACPI view功能,可查看ACPI Table
●DMIScope - 可查看DMI Table
●PCIScope - 可查看PCI/PCIE Info
●Key101.exe - 我T學長的以前同事key寫的(目前人還在我們公司某NB單位),功能同SE.EXE 但針對P公司BIOS撰寫!所以可讀取一些BIOS資訊!
●USBView.exe - 可列舉USB 設備在哪些Controller上.
以上工具的介紹可在下面網站下載或是得到相關資訊,至於相關版權問題請自行與作者洽詢!
Reference
http://ruexe.blogspot.com/
http://rweverything.phpnet.us/
http://www.tssc.de/index.htm
http://www.programmer-club.com
星期三, 9月 03, 2008
星期日, 8月 17, 2008
WinSAT
最近幫中華隊加油,真是越看越生氣! 今天早上看新聞還看到我們還有機會爭第六名,還一堆記者很高興的寫文章安慰自己,真是曾幾何時我們的棒球淪落到只能拿第六名!
但無論中華隊這次表現如何,他們代表著我們奮戰的精神! 畢竟比賽還沒結束,還是要奮戰到底!
創造另一個奇蹟吧,中華隊!!!
加油歸加油,今天要提到的主題是Vista 6001(SP1)下的一些內建工具中ㄧ個很實用的工具,他的名字叫做"WinSAT"
這個工具內建在Vista之中,你可以先開啟一個管理者權限的cmd,然後直接鍵入WinSAT後就可以執行,不過執行的時候有內建一些參數,所以你必須選擇你要的功能。
而這個工具有什麼用途呢? 這個工具可以當作是Benchmark 工具,用來測試你的系統! 像是CPU/Graphic ...等都可以拿來測試!
因為他是微軟內建的工具,所以由微軟的網站上可以得到相關的使用說明,請參閱下面連結:
詳細的WinSAT使用方式
由上面的連結中,你可以發現其他的內建工具的用法,找找看,或許你會發現更好玩的東西喔!
幾個測試範例:
1. WinSAT cpu d3d -objs C(20) -texshader -totalobj 100 -time 60 -v -compression
2.WinSAT cpu aurora -time 120 -v -encryption
3.WinSAT d3d -texshader -totalobj 300 -time 120 -v
Reference
http://technet.microsoft.com
但無論中華隊這次表現如何,他們代表著我們奮戰的精神! 畢竟比賽還沒結束,還是要奮戰到底!
創造另一個奇蹟吧,中華隊!!!
加油歸加油,今天要提到的主題是Vista 6001(SP1)下的一些內建工具中ㄧ個很實用的工具,他的名字叫做"WinSAT"
這個工具內建在Vista之中,你可以先開啟一個管理者權限的cmd,然後直接鍵入WinSAT後就可以執行,不過執行的時候有內建一些參數,所以你必須選擇你要的功能。
而這個工具有什麼用途呢? 這個工具可以當作是Benchmark 工具,用來測試你的系統! 像是CPU/Graphic ...等都可以拿來測試!
因為他是微軟內建的工具,所以由微軟的網站上可以得到相關的使用說明,請參閱下面連結:
詳細的WinSAT使用方式
由上面的連結中,你可以發現其他的內建工具的用法,找找看,或許你會發現更好玩的東西喔!
幾個測試範例:
1. WinSAT cpu d3d -objs C(20) -texshader -totalobj 100 -time 60 -v -compression
2.WinSAT cpu aurora -time 120 -v -encryption
3.WinSAT d3d -texshader -totalobj 300 -time 120 -v
Reference
http://technet.microsoft.com
標籤:
Windows 程式相關
星期一, 7月 28, 2008
MSN Messenger 8.5 故障排除
前幾天突然MSN 都不能連線,查詢狀態後發現是MSN Server掛掉的問題,所以一堆人早上都不能上線。
本來想說反正等一會兒後就應該可以上線了,看著其他同事們一個個都連上線後我開始懷疑我的系統有問題了。ㄧ開始只是覺得可能是我的MSN是屬於xxx@msn.com 可能伺服器不同於Hotmail ,所以想多在等等看好了,直到下了班回到家使用了較舊版的MSN 後才發現這是MSN 8.5的問題...
因此,自己思考了一下我在這些時間中系統變更了哪些東西:
1.安裝了小紅傘掃毒程式
2.更新了Windows Installer 3.0
3.更新了MSN8.5
4.掃了一些廣告 & Virus
5.安裝了MSNEdit
在判斷後覺得,應該是更新MSN 8.5 的問題,因為其他的部份會有關係的地方大概就是掃毒程式防火牆的設定,但是把防火牆關閉後還是無法用MSN 8.5 登入,可是我使用MSN8.5 工具->選項->連線設定->Http測試後,MSN回報的訊息是"成功,你可以連線至MSN 服務",因此我不覺得我的網路連線有問題(ㄧ般IE/Firefox 也可以正常顯示網頁),也不覺得是MSN伺服器的問題,因為點選MSN登入畫面上的"服務狀態"的回報結果是 【所有系統皆穩定執行中。】
如此令人詭異的測試結果讓我覺得應該找個舊版的MSN試試看,因此我拿了XP內建的MSN登入,結果如同預期的是可以正常登入,所以強烈的懷疑是MSN 8.5的設定有問題。
懷疑是MSN 8.5的設定有問題那會是誰造成的? 原本我是懷疑MSNEdit造成的,但是在我安裝MSNEdit前就已經不行登入,所以我還是懷疑是更新了 MSN 8.5 後的設定與我原先的MSN相衝突。
因此,這時候就使用了無敵刪除大法,呼叫出Regedit(開始->執行,鍵入"Regedit") ,然後把下面的鍵值找出來,並且全部刪除看看:
HKEY_CURRENT_USER/Software/Microsoft/MSNMessenger
刪除後,奇妙的事情就發生了,MSN 8.5能登入了....真是令人OOXX#>X@!....
不管如何,MSN又可以正常使用了......^^
MSN 故障排除的幾個要點:
1.確認IE 的Proxy 設定,因為MSN會參考他,另外如果你的Proxy需要使用者名稱/密碼,請至MSN->工具->選項->連線->連線設定, Http 輸入
2.確認IE設定正確 : 工具->網際網路選項->進階 使用SSL2.0與SSL3.0有打勾
3.確認防火牆設定 : 區域連線->內容->進階->Windows防火牆 ->設定值->例外
程式和服務: 新增程式 ->選Windows Live Messenger
如果上述的方式不行,則可以試試看:
1.關閉Proxy
2.關閉防火牆
3.刪除Reg鍵值
4.連絡你們家的MIS
[Note] MSN 8.5 軟體需求
XP SP2 (如果你不是SP2的話可能會不能用)
WindowsInstaller 3.0 (如果你想網路更新的話)
本來想說反正等一會兒後就應該可以上線了,看著其他同事們一個個都連上線後我開始懷疑我的系統有問題了。ㄧ開始只是覺得可能是我的MSN是屬於xxx@msn.com 可能伺服器不同於Hotmail ,所以想多在等等看好了,直到下了班回到家使用了較舊版的MSN 後才發現這是MSN 8.5的問題...
因此,自己思考了一下我在這些時間中系統變更了哪些東西:
1.安裝了小紅傘掃毒程式
2.更新了Windows Installer 3.0
3.更新了MSN8.5
4.掃了一些廣告 & Virus
5.安裝了MSNEdit
在判斷後覺得,應該是更新MSN 8.5 的問題,因為其他的部份會有關係的地方大概就是掃毒程式防火牆的設定,但是把防火牆關閉後還是無法用MSN 8.5 登入,可是我使用MSN8.5 工具->選項->連線設定->Http測試後,MSN回報的訊息是"成功,你可以連線至MSN 服務",因此我不覺得我的網路連線有問題(ㄧ般IE/Firefox 也可以正常顯示網頁),也不覺得是MSN伺服器的問題,因為點選MSN登入畫面上的"服務狀態"的回報結果是 【所有系統皆穩定執行中。】
如此令人詭異的測試結果讓我覺得應該找個舊版的MSN試試看,因此我拿了XP內建的MSN登入,結果如同預期的是可以正常登入,所以強烈的懷疑是MSN 8.5的設定有問題。
懷疑是MSN 8.5的設定有問題那會是誰造成的? 原本我是懷疑MSNEdit造成的,但是在我安裝MSNEdit前就已經不行登入,所以我還是懷疑是更新了 MSN 8.5 後的設定與我原先的MSN相衝突。
因此,這時候就使用了無敵刪除大法,呼叫出Regedit(開始->執行,鍵入"Regedit") ,然後把下面的鍵值找出來,並且全部刪除看看:
HKEY_CURRENT_USER/Software/Microsoft/MSNMessenger
刪除後,奇妙的事情就發生了,MSN 8.5能登入了....真是令人OOXX#>X@!....
不管如何,MSN又可以正常使用了......^^
MSN 故障排除的幾個要點:
1.確認IE 的Proxy 設定,因為MSN會參考他,另外如果你的Proxy需要使用者名稱/密碼,請至MSN->工具->選項->連線->連線設定, Http 輸入
2.確認IE設定正確 : 工具->網際網路選項->進階 使用SSL2.0與SSL3.0有打勾
3.確認防火牆設定 : 區域連線->內容->進階->Windows防火牆 ->設定值->例外
程式和服務: 新增程式 ->選Windows Live Messenger
如果上述的方式不行,則可以試試看:
1.關閉Proxy
2.關閉防火牆
3.刪除Reg鍵值
4.連絡你們家的MIS
[Note] MSN 8.5 軟體需求
XP SP2 (如果你不是SP2的話可能會不能用)
WindowsInstaller 3.0 (如果你想網路更新的話)
標籤:
Windows 程式相關
星期四, 7月 24, 2008
INT 15h/AX=E820h 程式範例
昨天下午拿起了ACPI Spec , 把之前還沒實做的INT15h E820h 部份拿起來練習了一下。
由Google大神找到的文件中的說明中可以了解到INT15h E820h 的用途和歷史,下面就我找到的文件中截取ㄧ部份出來給各位參考,如果要看全文的可以透過連結去查看我找到的那篇文章!
Linux MemoryCapacity Detection
OS必須知道系統實體記憶體的數量,才能夠有效的使用和管理這些實體記憶體。所以在booting階段,我們必須通過某種手段來檢測和獲取實體記憶體的總量。
由於在booting階段的絕大部分時間裏,主機處於Real Mode下,而在RealMode下,我們通過正常手段能夠訪問的實體記憶體最大只能達到1M+64K(在A20Gate被打開的情況下,否則,最大只能訪問1M),所以我們無法直接通過記憶體訪問來獲取記憶體總量。因此,剩下的唯一手段就是通過BIOS中斷。
但不幸的是,通過BIOS中斷獲取記憶體容量並非在所有情況都可以完全工作。
獲取機器記憶體容量的方法一般來講有三種方法,這三種方法都是基於BIOS INT15h中斷,它們的名稱依此為88h,E801h,E820h。
其中,88h方法是在Intel80286出現的那天起就存在的,後續的PC及其兼容機為了保持向下相容,都繼續保留了這種方法。因此,這種方法在所有的IBMPC及其兼容機上都存在,所以看起來,booting只需要這種方法就可以獲取實體記憶體總量,其他兩種方法似乎沒有存在的必要。但事實上,這種方法存在一個重要的缺陷,由於這種方法是在16-bit時代就存在的,所以,它通過16-bit寄存器來保存記憶體容量作為返回值。但16-bit所能夠表示的最大值是64KB。由於這種方法的返回值是以KB為單位,所以它能夠表示的系統最大實體記憶體容量為64 MB。而對於今天的PC機來說,64MB已經是很低的記憶體配置了,大多數PC機的實際實體記憶體配置都大於64 MB。
另外,需要注意的是,由於這種方法出現於Intel80286時代,而80286的24-bit位址匯流排能夠訪問的最大位址為16MB,所以,儘管這種方法使用16-bit寄存器能夠表示的最大記憶體數量為64MB,但標準的BIOS只允許通過這種方法獲取最大16 MB的實體記憶體數量。
為了能夠獲取大於64MB的記憶體,就必須通過另外兩種方法的一種。但並非每一台PC機都實現了這兩種方法或這兩種方法之一。
當今流行的桌面作業系統在Booting階段進行記憶體檢測的方法都是採用這三種方法,比如Microsoft WindowsNT,Linux等。所以在某些不支持E820h,E801h的PC上,它們也最多只能檢測到64 MB或16MB實體記憶體(依賴於88h的最大返回值限制)。
但請不必過分擔心,對於絕大多數現代PC機來說,至少提供了這兩種方法的一種;而對於過去的PC機,又很少有超過64MB的配置。從這個意義上來說,這已經足夠了。
INT 15h, AX=E820h Query SystemAddress Map
E820h只能用在Real Mode下使用
這個中斷調用返回所有被安裝在主機上的RAM,以及被BIOS所保留的實體記憶體範圍的記憶體映象。
Reference
http://docs.huihoo.com/gnu_linux/own_os/booting-memory_check_6.htm
Acpi Spec 3.0b
底下是範例程式下載以及執行後的結果,我是用7-Zip 免費壓縮軟體壓縮的,所以請使用最新版WinRar或是7-Zip 才能解壓縮喔...
點我下載E820範例程式 <~~記得在DOS下跑喔...
BassLow BaseHigh SizeLow SizeHigh Type
------------------------------------------------------
00000000 0000 0009FC00 0000 1 AddressRangeMemory(EfiLoaderCode)
0009FC00 0000 00000400 0000 2 AddressRangeMemory(EfiLoaderData)
000E0000 0000 00020000 0000 2 AddressRangeMemory(EfiLoaderData)
00100000 0000 363E6000 0000 1 AddressRangeMemory(EfiLoaderCode)
364E6000 0000 00003000 0000 4 AddressRangeMemory(EfiBootServiceData)
364E9000 0000 01583000 0000 1 AddressRangeMemory(EfiLoaderCode)
37A6C000 0000 00053000 0000 2 AddressRangeMemory(EfiLoaderData)
37ABF000 0000 000C6000 0000 1 AddressRangeMemory(EfiLoaderCode)
37B85000 0000 0003A000 0000 4 AddressRangeMemory(EfiBootServiceData)
37BBF000 0000 00025000 0000 1 AddressRangeMemory(EfiLoaderCode)
37BE4000 0000 00013000 0000 3 AddressRangeMemory(EfiBootServiceCode)
37BF7000 0000 00009000 0000 1 AddressRangeMemory(EfiLoaderCode)
37C00000 0000 08400000 0000 2 AddressRangeMemory(EfiLoaderData)
F8000000 0000 04000000 0000 2 AddressRangeMemory(EfiLoaderData)
FEC00000 0000 00001000 0000 2 AddressRangeMemory(EfiLoaderData)
FED10000 0000 00004000 0000 2 AddressRangeMemory(EfiLoaderData)
FED18000 0000 00002000 0000 2 AddressRangeMemory(EfiLoaderData)
FED1C000 0000 00004000 0000 2 AddressRangeMemory(EfiLoaderData)
FEE00000 0000 00001000 0000 2 AddressRangeMemory(EfiLoaderData)
FFF00000 0000 00100000 0000 2 AddressRangeMemory(EfiLoaderData)
看的出來這台是1MB 的BIOS ROM吧 ...^^
Dump Memory map v1.0.0 by Harrison Hsieh
由Google大神找到的文件中的說明中可以了解到INT15h E820h 的用途和歷史,下面就我找到的文件中截取ㄧ部份出來給各位參考,如果要看全文的可以透過連結去查看我找到的那篇文章!
Linux MemoryCapacity Detection
OS必須知道系統實體記憶體的數量,才能夠有效的使用和管理這些實體記憶體。所以在booting階段,我們必須通過某種手段來檢測和獲取實體記憶體的總量。
由於在booting階段的絕大部分時間裏,主機處於Real Mode下,而在RealMode下,我們通過正常手段能夠訪問的實體記憶體最大只能達到1M+64K(在A20Gate被打開的情況下,否則,最大只能訪問1M),所以我們無法直接通過記憶體訪問來獲取記憶體總量。因此,剩下的唯一手段就是通過BIOS中斷。
但不幸的是,通過BIOS中斷獲取記憶體容量並非在所有情況都可以完全工作。
獲取機器記憶體容量的方法一般來講有三種方法,這三種方法都是基於BIOS INT15h中斷,它們的名稱依此為88h,E801h,E820h。
其中,88h方法是在Intel80286出現的那天起就存在的,後續的PC及其兼容機為了保持向下相容,都繼續保留了這種方法。因此,這種方法在所有的IBMPC及其兼容機上都存在,所以看起來,booting只需要這種方法就可以獲取實體記憶體總量,其他兩種方法似乎沒有存在的必要。但事實上,這種方法存在一個重要的缺陷,由於這種方法是在16-bit時代就存在的,所以,它通過16-bit寄存器來保存記憶體容量作為返回值。但16-bit所能夠表示的最大值是64KB。由於這種方法的返回值是以KB為單位,所以它能夠表示的系統最大實體記憶體容量為64 MB。而對於今天的PC機來說,64MB已經是很低的記憶體配置了,大多數PC機的實際實體記憶體配置都大於64 MB。
另外,需要注意的是,由於這種方法出現於Intel80286時代,而80286的24-bit位址匯流排能夠訪問的最大位址為16MB,所以,儘管這種方法使用16-bit寄存器能夠表示的最大記憶體數量為64MB,但標準的BIOS只允許通過這種方法獲取最大16 MB的實體記憶體數量。
為了能夠獲取大於64MB的記憶體,就必須通過另外兩種方法的一種。但並非每一台PC機都實現了這兩種方法或這兩種方法之一。
當今流行的桌面作業系統在Booting階段進行記憶體檢測的方法都是採用這三種方法,比如Microsoft WindowsNT,Linux等。所以在某些不支持E820h,E801h的PC上,它們也最多只能檢測到64 MB或16MB實體記憶體(依賴於88h的最大返回值限制)。
但請不必過分擔心,對於絕大多數現代PC機來說,至少提供了這兩種方法的一種;而對於過去的PC機,又很少有超過64MB的配置。從這個意義上來說,這已經足夠了。
INT 15h, AX=E820h Query SystemAddress Map
E820h只能用在Real Mode下使用
這個中斷調用返回所有被安裝在主機上的RAM,以及被BIOS所保留的實體記憶體範圍的記憶體映象。
Reference
http://docs.huihoo.com/gnu_linux/own_os/booting-memory_check_6.htm
Acpi Spec 3.0b
底下是範例程式下載以及執行後的結果,我是用7-Zip 免費壓縮軟體壓縮的,所以請使用最新版WinRar或是7-Zip 才能解壓縮喔...
點我下載E820範例程式 <~~記得在DOS下跑喔...
BassLow BaseHigh SizeLow SizeHigh Type
------------------------------------------------------
00000000 0000 0009FC00 0000 1 AddressRangeMemory(EfiLoaderCode)
0009FC00 0000 00000400 0000 2 AddressRangeMemory(EfiLoaderData)
000E0000 0000 00020000 0000 2 AddressRangeMemory(EfiLoaderData)
00100000 0000 363E6000 0000 1 AddressRangeMemory(EfiLoaderCode)
364E6000 0000 00003000 0000 4 AddressRangeMemory(EfiBootServiceData)
364E9000 0000 01583000 0000 1 AddressRangeMemory(EfiLoaderCode)
37A6C000 0000 00053000 0000 2 AddressRangeMemory(EfiLoaderData)
37ABF000 0000 000C6000 0000 1 AddressRangeMemory(EfiLoaderCode)
37B85000 0000 0003A000 0000 4 AddressRangeMemory(EfiBootServiceData)
37BBF000 0000 00025000 0000 1 AddressRangeMemory(EfiLoaderCode)
37BE4000 0000 00013000 0000 3 AddressRangeMemory(EfiBootServiceCode)
37BF7000 0000 00009000 0000 1 AddressRangeMemory(EfiLoaderCode)
37C00000 0000 08400000 0000 2 AddressRangeMemory(EfiLoaderData)
F8000000 0000 04000000 0000 2 AddressRangeMemory(EfiLoaderData)
FEC00000 0000 00001000 0000 2 AddressRangeMemory(EfiLoaderData)
FED10000 0000 00004000 0000 2 AddressRangeMemory(EfiLoaderData)
FED18000 0000 00002000 0000 2 AddressRangeMemory(EfiLoaderData)
FED1C000 0000 00004000 0000 2 AddressRangeMemory(EfiLoaderData)
FEE00000 0000 00001000 0000 2 AddressRangeMemory(EfiLoaderData)
FFF00000 0000 00100000 0000 2 AddressRangeMemory(EfiLoaderData)
看的出來這台是1MB 的BIOS ROM吧 ...^^
Dump Memory map v1.0.0 by Harrison Hsieh
標籤:
IA32 相關基礎知識
星期二, 7月 22, 2008
CRB V.S ERB
公板,大家都這樣叫,CRB (Customer Reference Board) ,這是入行的時候一直聽到的名詞。
記得當入行的時候很多人都跟我說I晶片公司會出ㄧ個CRB 板子,然後我們也會有個CRB BIOS,剛開始的時候搞不清楚那是什麼,後來才慢慢的有些概念。
查詢了相關文獻中指出,以前晶片組廠商各家爭鳴,但是相容性卻是個最大的問題,後來就有些廠商乾脆就自己做塊板子然後把自己的晶片組放上去,順便跟客戶展示一下Performance ,這塊板子就是所謂的CRB,用來給客戶參考用的板子。
隨著時間的演變,系統廠便直接參考CRB的設計去設計出不同的系統出來,也就是我們現在在做的事情,這樣的好處是不用擔心太多相容性的問題,而且可以快速開發出機種。
有些系統廠可能直接拿CRB板子,上面可能就多加個USB 接口就是一個機種,然後就可以拿去賣了,當然也有些系統廠特別針對某些晶片功能去設計一些特別的Features,當然售價也就不同於直接拿CRB修改的機種。
ERB, Evaluation Reference Board 當某個新的晶片組在研發過程中,總是會需要有模擬的板子來測試,因此這類型的板子會在現成的Platform 基礎上,去配置出新的晶片組的線路,並且讓BIOS廠商開始Study ㄧ些相關問題(Bring up next BIOS code),由於他是模擬的環境,所以往往Bring up出來的BIOS code跟實際上新的晶片組的CRB BIOS code還是會有些差距。
實際上我並沒有參與過CRB/ERB開發過程,畢竟我是系統端的BIOS, 因此我不能確定我所述一定正確,如有誤的地方請大家不吝指正。
記得當入行的時候很多人都跟我說I晶片公司會出ㄧ個CRB 板子,然後我們也會有個CRB BIOS,剛開始的時候搞不清楚那是什麼,後來才慢慢的有些概念。
查詢了相關文獻中指出,以前晶片組廠商各家爭鳴,但是相容性卻是個最大的問題,後來就有些廠商乾脆就自己做塊板子然後把自己的晶片組放上去,順便跟客戶展示一下Performance ,這塊板子就是所謂的CRB,用來給客戶參考用的板子。
隨著時間的演變,系統廠便直接參考CRB的設計去設計出不同的系統出來,也就是我們現在在做的事情,這樣的好處是不用擔心太多相容性的問題,而且可以快速開發出機種。
有些系統廠可能直接拿CRB板子,上面可能就多加個USB 接口就是一個機種,然後就可以拿去賣了,當然也有些系統廠特別針對某些晶片功能去設計一些特別的Features,當然售價也就不同於直接拿CRB修改的機種。
ERB, Evaluation Reference Board 當某個新的晶片組在研發過程中,總是會需要有模擬的板子來測試,因此這類型的板子會在現成的Platform 基礎上,去配置出新的晶片組的線路,並且讓BIOS廠商開始Study ㄧ些相關問題(Bring up next BIOS code),由於他是模擬的環境,所以往往Bring up出來的BIOS code跟實際上新的晶片組的CRB BIOS code還是會有些差距。
實際上我並沒有參與過CRB/ERB開發過程,畢竟我是系統端的BIOS, 因此我不能確定我所述一定正確,如有誤的地方請大家不吝指正。
星期一, 7月 21, 2008
Verb Table v.s S3 resume
前幾天在英業達的網友小偉用msn問了我一個問題,有關於Verb Table 在S3回來後不正確的問題.
他人還在大陸打拼中,目前情況不明,也不知道能不能回的了台灣........在此希望他能順利解決問題,早點回家吧!
Verb Table , 一般我們在設定的時候就是拿著Data Sheet然後設定相關的設定值進去BIOS code或是偷懶點請教廠商設定值是什麼然後加入進去,而BIOS會自己透過相關介面寫入Audio device.
在bios的觀點中,我們進入S3 前我們會去存PCI Regs 以確保HDA 相關暫存器有回填正確,當 S3 Resume 後一般我們會去回填PCI Reg 但是不會去回填Verb Table , 頂多就是拿工具去看S3 resume後Verb table是否一樣(一般都一樣),所以進入S3的時候並不會把Verb Table儲存到RAM中. 以上是我原本接觸的這部分設定時候的認知........但是經過小偉一問,我才發現原來我錯了 >.<
目前查詢到的資料如下:
Windows XP 之前的作業系統 - S3 Resume 時 , BIOS 需要自己手動回填Verb Table ,因為OS不會幫你回填.
Vista - 作業系統"理論上應該會/看似"會幫你回填 ,不過我沒找到M$有相關的說明,只有在某"紅皮"的書裡面有提到(也有可能不會=.=), 因此我們BIOS端就不需要再去填 (因為我都是接觸到這種會自己填的OS , 所以讓我以為BIOS 不用再填 一次, 由此可知 bios的知識還真的不能以偏蓋全,而且多接觸不同種類的平台才能累積更多經驗 >.<)
由於我接觸的還是某大公司的晶片組 , 而情況大概就是這樣 , 在某本書上提到的資訊是屬於保密部分,所以我也不能說太清楚,請自行查閱有關這部分的說明. 至於其他家的晶片組請自行測試.
另外BIOS如果要回填Verb Table , 做法大同小異 , 就是註冊SMI Routine , 在S3 Resume的點去跑你的Routine , 然後自己在回填一次Verb Table就可以了!
至於註冊方式, 依照各家bios做法不同,所以請自行參考BIOS廠商的範例!
他人還在大陸打拼中,目前情況不明,也不知道能不能回的了台灣........在此希望他能順利解決問題,早點回家吧!
Verb Table , 一般我們在設定的時候就是拿著Data Sheet然後設定相關的設定值進去BIOS code或是偷懶點請教廠商設定值是什麼然後加入進去,而BIOS會自己透過相關介面寫入Audio device.
在bios的觀點中,我們進入S3 前我們會去存PCI Regs 以確保HDA 相關暫存器有回填正確,當 S3 Resume 後一般我們會去回填PCI Reg 但是不會去回填Verb Table , 頂多就是拿工具去看S3 resume後Verb table是否一樣(一般都一樣),所以進入S3的時候並不會把Verb Table儲存到RAM中. 以上是我原本接觸的這部分設定時候的認知........但是經過小偉一問,我才發現原來我錯了 >.<
目前查詢到的資料如下:
Windows XP 之前的作業系統 - S3 Resume 時 , BIOS 需要自己手動回填Verb Table ,因為OS不會幫你回填.
Vista - 作業系統"理論上應該會/看似"會幫你回填 ,不過我沒找到M$有相關的說明,只有在某"紅皮"的書裡面有提到(也有可能不會=.=), 因此我們BIOS端就不需要再去填 (因為我都是接觸到這種會自己填的OS , 所以讓我以為BIOS 不用再填 一次, 由此可知 bios的知識還真的不能以偏蓋全,而且多接觸不同種類的平台才能累積更多經驗 >.<)
由於我接觸的還是某大公司的晶片組 , 而情況大概就是這樣 , 在某本書上提到的資訊是屬於保密部分,所以我也不能說太清楚,請自行查閱有關這部分的說明. 至於其他家的晶片組請自行測試.
另外BIOS如果要回填Verb Table , 做法大同小異 , 就是註冊SMI Routine , 在S3 Resume的點去跑你的Routine , 然後自己在回填一次Verb Table就可以了!
至於註冊方式, 依照各家bios做法不同,所以請自行參考BIOS廠商的範例!
星期二, 7月 15, 2008
Legacy-Free Hardware and BIOS Requirements
http://www.microsoft.com/taiwan/whdc/archive/Lf.mspx
這篇文章中可以讓你看看BIOS的最小需求為何,以及文章內的相關連結可以看到更多有關於一台PC在設計上Microsoft 是如何與Intel 去制定一些規範。
參考資料
http://www.microsoft.com/
http://www.microsoft.com/taiwan/whdc/archive/pcguides.mspx
這篇文章中可以讓你看看BIOS的最小需求為何,以及文章內的相關連結可以看到更多有關於一台PC在設計上Microsoft 是如何與Intel 去制定一些規範。
參考資料
http://www.microsoft.com/
http://www.microsoft.com/taiwan/whdc/archive/pcguides.mspx
標籤:
IA32 相關基礎知識
星期四, 6月 19, 2008
NVRAM list v.s NVStore
最近接了一個新的案子,雖然還沒開始Run但是事前的準備也不能少,也因此遇到了新問題,所以在部落格留下紀錄以後好方便查詢!
在跟客戶接觸的過程中,他們要求我提供CMOS NVRAM List ,用過P公司的BIOS的人都知道, P公司會產生這個List ,而這個List其實就是對應我們在Setup Menu中的選項設定值(例如某個item內有Enable/Disable選項而選擇後的值會存放進去CMOS當中) ,有了這份List ,客戶就可以開發自己的工廠測試程式去修改CMOS內的設定值來達到他們的需求(不考慮Checksum問題時可以這樣做)。最常見的就是修改Boot Order (修改開機順序),當然這些工具還是需要BIOS端的支援啦!
而我的問題在於EFI架構中為了一些安全性的考量,已經建議這些設定值的存放地方改至NVStore,即直接寫入至BIOS ROM中的某個規劃出來的區塊,因此我沒辦法直接修改CMOS來達到修改某個item的設定值,除非你在POST的BIOS code中去讀取你自己定義的CMOS位置然後在去改變他,這部分我們學長已經是這樣子的方式來修改BootOrder!
方式一:
AP修改CMOS --> POST過程中BIOS去讀取CMOS值 -->BIOS修改至相關Variable位置
有關於NVStore部分,在不同的bios廠商中做法也是不見得會完全依照當初的建議去做,像是P公司現階段的BIOS code就比較尷尬...因為他不是完全的EFI 架構,所以有一部分還是存放在NVRAM 中 ,一部分是存放在NVStore ,所以在過度期中他還是有提供NVRAM list,只可惜這次的案子不是使用p公司的BIOS =.=!
路不通就自己通, 因此在EFI 架構下我自己寫了一個介面給AP端使用(修改cmos在由POST 開機時讀取出來修改的方式我學長已經實做成功,所以我才試試看改寫另一種方式),方式是透過SW SMI Driver來註冊一個SMI Routine ,然後在這個Routne中去得到AP端傳進來的RAM Buffer,而這塊RAM Buffer中說明了我要去修改/讀取哪一個NV Variable 以及要寫入/回傳的資料 ,因此在DOS或是Windows下就可以很方便的透過這個介面去修改設定值。
而ap端我是採用TC++ 3.0 先去配置一塊記憶體,然後把參數寫進去這塊記憶體,然後用ESI指向這塊記憶體,接著發送SW SMI ,如下面所示
type struct {
DWORD Protocol; (Byte/word/dword)
DWORD VarIndex;
DWORD VarData;
}OEM_BUFFER
STATUS OEM_SMI_Trigger(OEM_BUFFER *inputbuf,OEM_BUFFER *outputbuf)
{
AH=Select Fun (Read/Write)
AL=SW SMI function number
ESI=input buffer
EDI=output buffer
EBX = Signature '$OEM'
DX=B2h
}
方式二:
AP端將參數寫至RAM --> AP端設定好暫存器,指向存放參數的RAM --> AP端觸發SMI --> BIOS透過暫存器得到參數 --> BIOS SMM code設定相關Variable.
結論:
透過方式一的方式簡單又方便,但是缺點在於傳遞的資料量有限,且如果變數過多時會很麻煩!
透過方式二的方式複雜但是可以傳遞較大的資料量,應用也比較廣,變數過多也無所謂,因為BIOS端會把這些item都集中然後放在某個Structure中,所以只要指定好Index就可以了(以前叫做Token),其他應用可以類似寫一個燒BIOS ROM的介面,透過BIOS本身的Code去燒...目前某家EFI BIOS公司就是這樣子去開發Flash utility...
在跟客戶接觸的過程中,他們要求我提供CMOS NVRAM List ,用過P公司的BIOS的人都知道, P公司會產生這個List ,而這個List其實就是對應我們在Setup Menu中的選項設定值(例如某個item內有Enable/Disable選項而選擇後的值會存放進去CMOS當中) ,有了這份List ,客戶就可以開發自己的工廠測試程式去修改CMOS內的設定值來達到他們的需求(不考慮Checksum問題時可以這樣做)。最常見的就是修改Boot Order (修改開機順序),當然這些工具還是需要BIOS端的支援啦!
而我的問題在於EFI架構中為了一些安全性的考量,已經建議這些設定值的存放地方改至NVStore,即直接寫入至BIOS ROM中的某個規劃出來的區塊,因此我沒辦法直接修改CMOS來達到修改某個item的設定值,除非你在POST的BIOS code中去讀取你自己定義的CMOS位置然後在去改變他,這部分我們學長已經是這樣子的方式來修改BootOrder!
方式一:
AP修改CMOS --> POST過程中BIOS去讀取CMOS值 -->BIOS修改至相關Variable位置
有關於NVStore部分,在不同的bios廠商中做法也是不見得會完全依照當初的建議去做,像是P公司現階段的BIOS code就比較尷尬...因為他不是完全的EFI 架構,所以有一部分還是存放在NVRAM 中 ,一部分是存放在NVStore ,所以在過度期中他還是有提供NVRAM list,只可惜這次的案子不是使用p公司的BIOS =.=!
路不通就自己通, 因此在EFI 架構下我自己寫了一個介面給AP端使用(修改cmos在由POST 開機時讀取出來修改的方式我學長已經實做成功,所以我才試試看改寫另一種方式),方式是透過SW SMI Driver來註冊一個SMI Routine ,然後在這個Routne中去得到AP端傳進來的RAM Buffer,而這塊RAM Buffer中說明了我要去修改/讀取哪一個NV Variable 以及要寫入/回傳的資料 ,因此在DOS或是Windows下就可以很方便的透過這個介面去修改設定值。
而ap端我是採用TC++ 3.0 先去配置一塊記憶體,然後把參數寫進去這塊記憶體,然後用ESI指向這塊記憶體,接著發送SW SMI ,如下面所示
type struct {
DWORD Protocol; (Byte/word/dword)
DWORD VarIndex;
DWORD VarData;
}OEM_BUFFER
STATUS OEM_SMI_Trigger(OEM_BUFFER *inputbuf,OEM_BUFFER *outputbuf)
{
AH=Select Fun (Read/Write)
AL=SW SMI function number
ESI=input buffer
EDI=output buffer
EBX = Signature '$OEM'
DX=B2h
}
方式二:
AP端將參數寫至RAM --> AP端設定好暫存器,指向存放參數的RAM --> AP端觸發SMI --> BIOS透過暫存器得到參數 --> BIOS SMM code設定相關Variable.
結論:
透過方式一的方式簡單又方便,但是缺點在於傳遞的資料量有限,且如果變數過多時會很麻煩!
透過方式二的方式複雜但是可以傳遞較大的資料量,應用也比較廣,變數過多也無所謂,因為BIOS端會把這些item都集中然後放在某個Structure中,所以只要指定好Index就可以了(以前叫做Token),其他應用可以類似寫一個燒BIOS ROM的介面,透過BIOS本身的Code去燒...目前某家EFI BIOS公司就是這樣子去開發Flash utility...
標籤:
IA32 相關基礎知識
星期一, 5月 26, 2008
記得要報稅喔~~~
每年到了這個時候就是要繳錢給國家的時候,每次到了這個時候就會覺得為什麼要把錢拿給那些能力很差的政客花? 不過抱怨歸抱怨...錢還是要乖乖的繳~~做好國民的義務!!!
這邊就整理一下資料給各位參考,看你每年要繳多少錢給國家:
Q1: 收入多少以下可以不用繳錢 ?
A1: 目前假設你是單身,依照規定, 綜所稅免稅額目前是77000,而薪資特別扣除額是78000,個人標準扣除額46000元,因此把這三個加起來一共是201000元,所以你的年收入超過這個數值你就一定要繳稅。
Q2: 繳多少稅? 乘多少百分比?
A2: 目前繳稅的公式如下 :
累進稅率速算公式 所得淨額 x 稅率 - 累進差額 = 應納稅額
第1等 : 0~370000 x 6% - 0
第2等 : 370001~990000 x 13% - 25900
第3等 : 990001~1980,000 x 21% - 105100
第4等 : 1980,001~3720000 x 30% - 283300
第5等 : 3720001以上 x 40% - 655300
我大致上解釋一下意義,假設你的年收入70萬,你扶養了一些人(可以有免稅額,簡單說就是政府假設每年你會花掉多少錢去養一個人,這部分算你花掉的所以不扣你稅)所以扣除掉這些免稅額,假設剩下來的是40萬,你就坐落在第2等的計算方式,因此你要繳的錢就是 40萬*13%-25900 = 26100
此時,如果你的公司有先幫你繳稅,假設先幫你繳了2000(政府已經收了你的錢) 則你實際要繳的稅就還要減去2000,應此實際你要在繳的稅就剩下 24100 。
至於節稅方式就是看哪個對你有利你就用哪一個:
例如每個人的標準扣除額46000, 假設你去年有捐錢做善事/買保險 而這些花掉的錢 > 46000 那你就可以選擇用列舉方式來告訴政府說我多花掉的錢已經大於46000 所以你要少扣我一些錢
因此有錢人喜歡做善事~~~
這邊就整理一下資料給各位參考,看你每年要繳多少錢給國家:
Q1: 收入多少以下可以不用繳錢 ?
A1: 目前假設你是單身,依照規定, 綜所稅免稅額目前是77000,而薪資特別扣除額是78000,個人標準扣除額46000元,因此把這三個加起來一共是201000元,所以你的年收入超過這個數值你就一定要繳稅。
Q2: 繳多少稅? 乘多少百分比?
A2: 目前繳稅的公式如下 :
累進稅率速算公式 所得淨額 x 稅率 - 累進差額 = 應納稅額
第1等 : 0~370000 x 6% - 0
第2等 : 370001~990000 x 13% - 25900
第3等 : 990001~1980,000 x 21% - 105100
第4等 : 1980,001~3720000 x 30% - 283300
第5等 : 3720001以上 x 40% - 655300
我大致上解釋一下意義,假設你的年收入70萬,你扶養了一些人(可以有免稅額,簡單說就是政府假設每年你會花掉多少錢去養一個人,這部分算你花掉的所以不扣你稅)所以扣除掉這些免稅額,假設剩下來的是40萬,你就坐落在第2等的計算方式,因此你要繳的錢就是 40萬*13%-25900 = 26100
此時,如果你的公司有先幫你繳稅,假設先幫你繳了2000(政府已經收了你的錢) 則你實際要繳的稅就還要減去2000,應此實際你要在繳的稅就剩下 24100 。
至於節稅方式就是看哪個對你有利你就用哪一個:
例如每個人的標準扣除額46000, 假設你去年有捐錢做善事/買保險 而這些花掉的錢 > 46000 那你就可以選擇用列舉方式來告訴政府說我多花掉的錢已經大於46000 所以你要少扣我一些錢
因此有錢人喜歡做善事~~~
星期一, 5月 19, 2008
DOS Dump
之前寫了一個Windows版的Dump BIOS工具,所以順便寫一個DOS版的工具,不過我沒把讀取到的BIOS資料輸出到檔案,而只有顯示在螢幕上,如果大家有興趣可以下載回去看看。
不寫到檔案的原因在於DOS存取USB隨身碟要ㄧ段時間,所以我就沒做這部份的功能,但是如果大家有興趣把BIOS內容存到隨身碟然後在慢慢分析,你可以試著使用DOS重新導向功能來達到這個目的。
使用DOS重新導向的做法如下,不過我要事先提醒你,很花時間喔!!!
C:\> Dosdump /4k > BIOS.bin (輸出4k大小的BIOS內容到BIOS.bin檔案中)
這邊說的4K是指,從FFFF_FFFF往下算4K Bytes
DOSDump.exe
Usage:
Arg1 :
/Byte /word /dword 只顯示256 Bytes ,只是自己好玩,模仿一下不同格式的顯示!
/4k /64k /128k /512k/1M/2M 看你要多大就設定多大
Arg2: /p 顯示的時候要不要等待按鍵,如果你想慢慢看,你可以用這個參數
EX1:
C:\> DOSDUMP /4k /p
EX2:
C:\>DOSDUMP /2M
工具與原理:
我是使用DOS的C語言編譯器去寫的,因為是16 bit編譯器,所以要自己切換CPU工作模式,做法如同BigRealmode方式只是換成C的寫法而已,而副程式是採用__emit__(); 方式內崁機器碼的方式撰寫! 以避免16 bit編譯器無法使用"32bit暫存器的問題",例如: EAX..
點我下載
補充
放一個新版的DOSDump v1.0,增加一個小功能,你可以用來指定你要看的記憶體位址的內容,或是針對某個範圍內去搜尋某個字串。
/a : Start Address
/s: size (Hex)
/f:find string
/p: pause
ex1: 在FFE00000~FFFFFFFF內搜尋字串"_DMI" ,如果有找到則顯示起始位址開始的256 bytes. ,假如找到的位址在FFEB0000h,則會顯示FFEB0000h~FFEB00FFh的內容。
DOSDump /a:FFE00000 /s:200000 /f:_DMI
ex2: 顯示某個位址開始,大小為4K的內容,且每256 bytes暫停一下
DOSDump /a:F0000 /s:1000 /p
新版的工具,請點我下載
※請在DOS環境使用
※參數後面直接打16進制的位址,請不要加0x..或是xxxh 因為我沒防呆喔!
※工具寫的很陽春,沒有防呆,也沒錯例外處理,所以請多多包涵! ^^
不寫到檔案的原因在於DOS存取USB隨身碟要ㄧ段時間,所以我就沒做這部份的功能,但是如果大家有興趣把BIOS內容存到隨身碟然後在慢慢分析,你可以試著使用DOS重新導向功能來達到這個目的。
使用DOS重新導向的做法如下,不過我要事先提醒你,很花時間喔!!!
C:\> Dosdump /4k > BIOS.bin (輸出4k大小的BIOS內容到BIOS.bin檔案中)
這邊說的4K是指,從FFFF_FFFF往下算4K Bytes
DOSDump.exe
Usage:
Arg1 :
/Byte /word /dword 只顯示256 Bytes ,只是自己好玩,模仿一下不同格式的顯示!
/4k /64k /128k /512k/1M/2M 看你要多大就設定多大
Arg2: /p 顯示的時候要不要等待按鍵,如果你想慢慢看,你可以用這個參數
EX1:
C:\> DOSDUMP /4k /p
EX2:
C:\>DOSDUMP /2M
工具與原理:
我是使用DOS的C語言編譯器去寫的,因為是16 bit編譯器,所以要自己切換CPU工作模式,做法如同BigRealmode方式只是換成C的寫法而已,而副程式是採用__emit__(); 方式內崁機器碼的方式撰寫! 以避免16 bit編譯器無法使用"32bit暫存器的問題",例如: EAX..
點我下載
補充
放一個新版的DOSDump v1.0,增加一個小功能,你可以用來指定你要看的記憶體位址的內容,或是針對某個範圍內去搜尋某個字串。
/a : Start Address
/s: size (Hex)
/f:find string
/p: pause
ex1: 在FFE00000~FFFFFFFF內搜尋字串"_DMI" ,如果有找到則顯示起始位址開始的256 bytes. ,假如找到的位址在FFEB0000h,則會顯示FFEB0000h~FFEB00FFh的內容。
DOSDump /a:FFE00000 /s:200000 /f:_DMI
ex2: 顯示某個位址開始,大小為4K的內容,且每256 bytes暫停一下
DOSDump /a:F0000 /s:1000 /p
新版的工具,請點我下載
※請在DOS環境使用
※參數後面直接打16進制的位址,請不要加0x..或是xxxh 因為我沒防呆喔!
※工具寫的很陽春,沒有防呆,也沒錯例外處理,所以請多多包涵! ^^
星期五, 5月 16, 2008
DOS Reboot~~
DOS ,一個很經典的作業系統,但是我對他的了解還是不夠清楚。
以前如果要在DOS下做Reboot ,在我寫程式的經驗中不外乎就是下面幾種方式:
1. Jmp FFFF:0
2.KBC Cmd FEh
3.CF9h
4.Port 92h
沒想到,在我接觸麥金塔作業系統測試工作的時間中竟然讓我荒廢了那麼多的該學習的知識沒去學,果然前一份工作不應該搞太久的 >.< ! 亡羊補牢,所以我在處理ㄧ些BIOS Bug的過程中所找到的相關文獻中發現,原來Jmp FFFF:0 這個動作不是那麼的安全,有可能會造成問題,這個問題還真的很特別。 因為在一些含有記憶體管理的作業系統中,原來在做這個動作前還需要廣播給相關的程式去做一些動作,例如通知EMM386去清除一些相關設定..等,等他清除完畢後在做Jmp FFFF:0 才不會造成一些不可預期的事情,而這個方式是透過INT 15h/AH=4F來做的。 話雖如此,一般應用程式在Jmp FFFF:0 之後,通常都會Jmp F000:E05B的位址,而這個位址內會放著"相容性的BIOS程式碼位址",簡言之這邊就是BIOS負責Reboot動作的程式碼。 而這段程式碼內,每家的作法都不太ㄧ樣,但最後都會做ㄧ個Warm Boot動作,即CPU Reset。 當CPU Reset後,會從4G頂端開始執行,因此在做Warm boot前,BIOS一般都會把A20打開,然後才做Warm Boot。 而4G頂端的BIOS程式碼,一般都會去判斷ㄧ個條件(目前),而這個條件就是判斷系統是Warm boot/Cold boot ,如果是Warm boot,則BIOS會在做ㄧ次Cold boot,因為做了Cold boot,所以就算沒有透過INT15h廣播,你重新進入到DOS下時也不會有問題。 所以看起來整個DOS下的流程如下所示:
1. DOS下的AP要做Reboot
2.DOS下的AP透過INT15去廣播,告知相關軟體要重新開機了
3.相關軟體因為有Hook INT15h,所以得知要關機了,所以各自負責相關需要關閉或是清理的部份。
4.控制權回到DOS下的AP,此AP做了一個Jum FFFF:0的動作
5.控制權交給BIOS,BIOS檢查相關Flag,BIOS廣播INT15h,BIOS設定BDA Flag=1234h,BIOS設定System Flag,BIOS開啟A20,BIOS做ㄧ個Warm boot(KBC Feh或是CF9)
6.系統重新開機,CPU從4G那邊的Code開始跑
7.BIOS檢查System Flag , 如果是Warm boot -->在做ㄧ次Cold boot,此次 Cold boot 會清除所有的Flag,所以下次從4G那邊開始Run的時候就不會檢查到Warm boot -->正常開機程序
[註1] 開啟A20有三種方式
1.KBC Cmd (D1h - 設定 , D0h讀取狀態)
如果你有I公司的Kx工具 ,你可以使用下列參數去做:
Enable: Kx Cd1 W02 (寫入02或是FEh都可以,因為A20 在bit 1)
Disable: Kx Cd1 W00 (寫入00或是FDh都可以,因為A20 在bit 1)
Read Status: Kx Cd0 I1 (I1,代表讀取1次)
2.Port 92h
需查看EDS Spec,一般都在Bit 1=A20
Enable : Out 92h,02h (或是FEh)
Disable: Out 92h,00h(或是FDh)
3.Call INT 15h/AH=24 (Fast A20)
AL=01 - Enable A20
AL=00 - Disable A20
其實呼叫的中斷內所做的事情就是方式2的方式
[註2] A20開關程式的撰寫
ㄧ般我們會先去呼叫INT15h來開啟,如果失敗則試試看Port 92h方式,如果在失敗才又使用KBC Cmd方式,你可能會問說INT15h不是跟Port 92hㄧ樣嗎,對他們最後都是ㄧ樣方式,但是INT15h是透過BIOS提供的中斷服務程式介面,簡單說就是BIOS可能沒寫INT 15h Services,所以你只好手動去開啟。
[註3]A20是否開啟成功
檢查方式是透過檢查記憶體內容是否ㄧ樣,因為如果A20沒有開啟成功,則記憶體會迴繞,因此你去讀取0000:0000 所看到的資料會跟FFFF:10所看到的一樣,因此我們去比對這兩個記憶體的內容:
相同 : A20開啟失敗
不相同: A20開啟成功,也就是可以存取1M以上的內容
Debug.com方式:
-D 0000:0000
-D FFFF:0010
[註4] INT 15h/AH=4F廣播
1.呼叫INT15h廣播前,須手動設定BDA 40:17內的旗標,bit 3:2=11,也就是填0Ch (Ctrl與Alt Flag=1)
2.呼叫INT15h時,須把DEL key的Scancode放在AL,即AL=53h
其實就是模擬Ctrl+Alt+Del動作,很類似Windows底下的API去通知Driver關閉他們負責的設備,其實DOS下也有,酷吧!
Win98 - 本身沒有記憶體管理,除非掛Himem.sys 掛的時候他會去呼叫INT15h/E820h來得到記憶體容量,因此沒掛的時候你在DOS下A20應該是預設被關閉的,如果有被打開應該就是BIOS開的。
WinME-本身就有記憶體管理,自己會開啟A20,開啟的時候不ㄧ定是透過KBC/Port 92h ,我還沒找到判斷的地方,因此目前我手上的機器中所看到的現象是有可能OS會透過Port 92h來開,也有可能會透過KBC來開,因此BIOS端應該有地方提供資訊,不過我還沒找到~~~
[註5] BIOS真的要開啟A20後ㄧ定要做Warm Boot嗎?
上述的動作是:
Jmp F000:E05b -->BIOS Enable A20-->BIOS檢查/設定Flag -->BIOS Warm boot --> CPU Frist Instruction --> BIOS check Cold/Warm boot --> If warm boot , do cold boot.
我懷疑某些BIOS廠商的動作會變成是:
Jmp F000:E05b -->BIOS Enable A20 --> BIOS檢查/設定Flag -->BIOS check System Flag --> If System flag=warm boot --> do cold boot.
兩者的差別在於有沒有回到4G 頂端。
[註6] Ctrl+Alt+Del
這個對我來說還是個謎,因為DOS會去Hook INT09h,所以搞不清楚到底是誰去判斷Ctrl+Alt+Del,有家BIOS廠商的程式碼中看起來DOS並不會去處理他們,所以會回到BIOS的INT09h中斷去處理,因此我可以在這邊去做ㄧ些事情,但是又有的BIOS廠商在Win98時會回到INT09h,但是在WinME DOS環境下時我又攔截不到OS會把控制權交回去BIOS INT09h,所以只能說 OEM/ODM端的BIOS能拿到的資料還是有限,有時候想追問題也是心有餘而力不足啦~~~
P.S 有時間在去寫一個Hook INT09h來自己處理Ctrl+Alt+Del好了 >.<
以上純屬個人實驗筆記,未必正確!請大家不吝指正!
以前如果要在DOS下做Reboot ,在我寫程式的經驗中不外乎就是下面幾種方式:
1. Jmp FFFF:0
2.KBC Cmd FEh
3.CF9h
4.Port 92h
沒想到,在我接觸麥金塔作業系統測試工作的時間中竟然讓我荒廢了那麼多的該學習的知識沒去學,果然前一份工作不應該搞太久的 >.< ! 亡羊補牢,所以我在處理ㄧ些BIOS Bug的過程中所找到的相關文獻中發現,原來Jmp FFFF:0 這個動作不是那麼的安全,有可能會造成問題,這個問題還真的很特別。 因為在一些含有記憶體管理的作業系統中,原來在做這個動作前還需要廣播給相關的程式去做一些動作,例如通知EMM386去清除一些相關設定..等,等他清除完畢後在做Jmp FFFF:0 才不會造成一些不可預期的事情,而這個方式是透過INT 15h/AH=4F來做的。 話雖如此,一般應用程式在Jmp FFFF:0 之後,通常都會Jmp F000:E05B的位址,而這個位址內會放著"相容性的BIOS程式碼位址",簡言之這邊就是BIOS負責Reboot動作的程式碼。 而這段程式碼內,每家的作法都不太ㄧ樣,但最後都會做ㄧ個Warm Boot動作,即CPU Reset。 當CPU Reset後,會從4G頂端開始執行,因此在做Warm boot前,BIOS一般都會把A20打開,然後才做Warm Boot。 而4G頂端的BIOS程式碼,一般都會去判斷ㄧ個條件(目前),而這個條件就是判斷系統是Warm boot/Cold boot ,如果是Warm boot,則BIOS會在做ㄧ次Cold boot,因為做了Cold boot,所以就算沒有透過INT15h廣播,你重新進入到DOS下時也不會有問題。 所以看起來整個DOS下的流程如下所示:
1. DOS下的AP要做Reboot
2.DOS下的AP透過INT15去廣播,告知相關軟體要重新開機了
3.相關軟體因為有Hook INT15h,所以得知要關機了,所以各自負責相關需要關閉或是清理的部份。
4.控制權回到DOS下的AP,此AP做了一個Jum FFFF:0的動作
5.控制權交給BIOS,BIOS檢查相關Flag,BIOS廣播INT15h,BIOS設定BDA Flag=1234h,BIOS設定System Flag,BIOS開啟A20,BIOS做ㄧ個Warm boot(KBC Feh或是CF9)
6.系統重新開機,CPU從4G那邊的Code開始跑
7.BIOS檢查System Flag , 如果是Warm boot -->在做ㄧ次Cold boot,此次 Cold boot 會清除所有的Flag,所以下次從4G那邊開始Run的時候就不會檢查到Warm boot -->正常開機程序
[註1] 開啟A20有三種方式
1.KBC Cmd (D1h - 設定 , D0h讀取狀態)
如果你有I公司的Kx工具 ,你可以使用下列參數去做:
Enable: Kx Cd1 W02 (寫入02或是FEh都可以,因為A20 在bit 1)
Disable: Kx Cd1 W00 (寫入00或是FDh都可以,因為A20 在bit 1)
Read Status: Kx Cd0 I1 (I1,代表讀取1次)
2.Port 92h
需查看EDS Spec,一般都在Bit 1=A20
Enable : Out 92h,02h (或是FEh)
Disable: Out 92h,00h(或是FDh)
3.Call INT 15h/AH=24 (Fast A20)
AL=01 - Enable A20
AL=00 - Disable A20
其實呼叫的中斷內所做的事情就是方式2的方式
[註2] A20開關程式的撰寫
ㄧ般我們會先去呼叫INT15h來開啟,如果失敗則試試看Port 92h方式,如果在失敗才又使用KBC Cmd方式,你可能會問說INT15h不是跟Port 92hㄧ樣嗎,對他們最後都是ㄧ樣方式,但是INT15h是透過BIOS提供的中斷服務程式介面,簡單說就是BIOS可能沒寫INT 15h Services,所以你只好手動去開啟。
[註3]A20是否開啟成功
檢查方式是透過檢查記憶體內容是否ㄧ樣,因為如果A20沒有開啟成功,則記憶體會迴繞,因此你去讀取0000:0000 所看到的資料會跟FFFF:10所看到的一樣,因此我們去比對這兩個記憶體的內容:
相同 : A20開啟失敗
不相同: A20開啟成功,也就是可以存取1M以上的內容
Debug.com方式:
-D 0000:0000
-D FFFF:0010
[註4] INT 15h/AH=4F廣播
1.呼叫INT15h廣播前,須手動設定BDA 40:17內的旗標,bit 3:2=11,也就是填0Ch (Ctrl與Alt Flag=1)
2.呼叫INT15h時,須把DEL key的Scancode放在AL,即AL=53h
其實就是模擬Ctrl+Alt+Del動作,很類似Windows底下的API去通知Driver關閉他們負責的設備,其實DOS下也有,酷吧!
Win98 - 本身沒有記憶體管理,除非掛Himem.sys 掛的時候他會去呼叫INT15h/E820h來得到記憶體容量,因此沒掛的時候你在DOS下A20應該是預設被關閉的,如果有被打開應該就是BIOS開的。
WinME-本身就有記憶體管理,自己會開啟A20,開啟的時候不ㄧ定是透過KBC/Port 92h ,我還沒找到判斷的地方,因此目前我手上的機器中所看到的現象是有可能OS會透過Port 92h來開,也有可能會透過KBC來開,因此BIOS端應該有地方提供資訊,不過我還沒找到~~~
[註5] BIOS真的要開啟A20後ㄧ定要做Warm Boot嗎?
上述的動作是:
Jmp F000:E05b -->BIOS Enable A20-->BIOS檢查/設定Flag -->BIOS Warm boot --> CPU Frist Instruction --> BIOS check Cold/Warm boot --> If warm boot , do cold boot.
我懷疑某些BIOS廠商的動作會變成是:
Jmp F000:E05b -->BIOS Enable A20 --> BIOS檢查/設定Flag -->BIOS check System Flag --> If System flag=warm boot --> do cold boot.
兩者的差別在於有沒有回到4G 頂端。
[註6] Ctrl+Alt+Del
這個對我來說還是個謎,因為DOS會去Hook INT09h,所以搞不清楚到底是誰去判斷Ctrl+Alt+Del,有家BIOS廠商的程式碼中看起來DOS並不會去處理他們,所以會回到BIOS的INT09h中斷去處理,因此我可以在這邊去做ㄧ些事情,但是又有的BIOS廠商在Win98時會回到INT09h,但是在WinME DOS環境下時我又攔截不到OS會把控制權交回去BIOS INT09h,所以只能說 OEM/ODM端的BIOS能拿到的資料還是有限,有時候想追問題也是心有餘而力不足啦~~~
P.S 有時間在去寫一個Hook INT09h來自己處理Ctrl+Alt+Del好了 >.<
以上純屬個人實驗筆記,未必正確!請大家不吝指正!
標籤:
IA32 相關基礎知識
星期四, 5月 15, 2008
Windows下存取4G Memory方式
存取的方式有很多種,我就列幾種比較常看到的方式:
1. WinIo -有開放原始碼,有興趣的可以研究一下,透過Driver層下去做
2. 呼叫NTDll.dll內的函數 - 這是原本我在XP的做法如下!
wchar_t strPath[30]=L"\\device\\physicalmemory";
LoadLibrary("ntdll.dll");
然後使用下列函數:
ZwOpenSection
ZwMapViewOfSection
ZwUnmapViewOfSection
這些函數可以對實體記憶體映射,不過這個方式在Vista下會無法使用,看樣子VISTA基於安全性考量已經這些功能拿掉了!
3.而在Vista下我目前是直接寫IO Driver,然後AP去Call我自己寫的Driver來讀,作法其實是如同WinIO.. ,只是我把我要的功能抽取出來而已,這個方式就是我用來撰寫DumpBIOS這個工具的作法,原本是用方式2,但是Vista不支援因此才改成方式3,你可能會問我為什麼不用方式1 ?
沒為什麼,就是想自己寫個IO Driver而已~~
Reference
Microsoft
Google
1. WinIo -有開放原始碼,有興趣的可以研究一下,透過Driver層下去做
2. 呼叫NTDll.dll內的函數 - 這是原本我在XP的做法如下!
wchar_t strPath[30]=L"\\device\\physicalmemory";
LoadLibrary("ntdll.dll");
然後使用下列函數:
ZwOpenSection
ZwMapViewOfSection
ZwUnmapViewOfSection
這些函數可以對實體記憶體映射,不過這個方式在Vista下會無法使用,看樣子VISTA基於安全性考量已經這些功能拿掉了!
3.而在Vista下我目前是直接寫IO Driver,然後AP去Call我自己寫的Driver來讀,作法其實是如同WinIO.. ,只是我把我要的功能抽取出來而已,這個方式就是我用來撰寫DumpBIOS這個工具的作法,原本是用方式2,但是Vista不支援因此才改成方式3,你可能會問我為什麼不用方式1 ?
沒為什麼,就是想自己寫個IO Driver而已~~
Reference
Microsoft
標籤:
Windows 程式相關
星期三, 5月 14, 2008
你看過古董嗎?
個人電腦發展至今已經數十年了,我當初最早接觸到的電腦是80386年代,在更早之前的連看都沒看過,而教科書上偶爾也會放一些老電腦的照片讓大家看看科技是進步的多麼的快速ㄚ!
我在查資料的過程中遇見了這個網站,他整理了一些老古董電腦,還很認真的幫他寫上規格註解,如果大家有興趣的話可以去這個網站看看,順便懷舊一下喔~~~
http://www.vintage-computer.com/ibm_pc.shtml
我在查資料的過程中遇見了這個網站,他整理了一些老古董電腦,還很認真的幫他寫上規格註解,如果大家有興趣的話可以去這個網站看看,順便懷舊一下喔~~~
http://www.vintage-computer.com/ibm_pc.shtml
星期二, 5月 13, 2008
BIOS Data Area
放一些查資料的網站方便查閱一些資料。
[注意] UEFI Class 3 (Pure UEFI) BIOS 就可能不會完全使用這些參考位址,這部分請自行聯繫BIOS vendor或是你的BIOS core team確認.BDA - BIOS Data Area - PC Memory Map
Address Size Description
00:00 256dwords Interrupt vector table
30:00 256bytes Stack area used during post and bootstrap
40:00 word COM1 port address
40:02 word COM2 port address
40:04 word COM3 port address
40:06 word COM4 port address
40:08 word LPT1 port address
40:0A word LPT2 port address
40:0C word LPT3 port address
40:0E word LPT4 port address (except PS/2)
Extended BIOS Data Area segment (PS/2, see EBDA)
40:10 2 bytes Equipment list flags (see INT 11)
|7|6|5|4|3|2|1|0| 40:10 (value in INT 11 register AL)
| | | | | | | `- IPL diskette installed
| | | | | | `-- math coprocessor
| | | | |-+-- old PC system board RAM < 256K
| | | | | `-- pointing device installed (PS/2)
| | | | `--- not used on PS/2
| | `------ initial video mode
`--------- # of diskette drives, less 1
|7|6|5|4|3|2|1|0| 40:11 (value in INT 11 register AH)
| | | | | | | `- 0 if DMA installed
| | | | `------ number of serial ports
| | | `------- game adapter
| | `-------- not used, internal modem (PS/2)
`----------- number of printer ports
40:12 byte PCjr: infrared keyboard link error count
40:13 word Memory size in Kbytes (see INT 12)
40:15 byte Reserved
40:16 byte PS/2 BIOS control flags
40:17 byte Keyboard flag byte 0 (see KB FLAGS)
|7|6|5|4|3|2|1|0| keyboard flag byte 0
| | | | | | | `--- right shift key depressed
| | | | | | `---- left shift key depressed
| | | | | `----- CTRL key depressed
| | | | `------ ALT key depressed
| | | `------- scroll-lock is active
| | `-------- num-lock is active
| `--------- caps-lock is active
`---------- insert is active
40:18 byte Keyboard flag byte 1 (see KB FLAGS)
|7|6|5|4|3|2|1|0| keyboard flag byte
| | | | | | | `--- left CTRL key depressed
| | | | | | `---- left ALT key depressed
| | | | | `----- system key depressed and held
| | | | `------ suspend key has been toggled
| | | `------- scroll lock key is depressed
| | `-------- num-lock key is depressed
| `--------- caps-lock key is depressed
`---------- insert key is depressed
40:19 byte Storage for alternate keypad entry
40:1A word Offset from 40:00 to keyboard buffer head
40:1C word Offset from 40:00 to keyboard buffer tail
40:1E 32bytes Keyboard buffer (circular queue buffer)
40:3E byte Drive recalibration status
|7|6|5|4|3|2|1|0| drive recalibration status
| | | | | | | `-- 1=recalibrate drive 0
| | | | | | `--- 1=recalibrate drive 1
| | | | | `---- 1=recalibrate drive 2
| | | | `----- 1=recalibrate drive 3
| `---------- unused
`----------- 1=working interrupt flag
40:3F byte Diskette motor status
|7|6|5|4|3|2|1|0| diskette motor status
| | | | | | | `-- 1=drive 0 motor on
| | | | | | `--- 1=drive 1 motor on
| | | | | `---- 1=drive 2 motor on
| | | | `----- 1=drive 3 motor on
| `---------- unused
`----------- 1=write operation
40:40 byte Motor shutoff counter (decremented by INT 8)
40:41 byte Status of last diskette operation (see INT 13,1)
|7|6|5|4|3|2|1|0| status of last diskette operation
| | | | | | | `--- invalid diskette command
| | | | | | `---- diskette address mark not found
| | | | | `----- sector not found
| | | | `------ diskette DMA error
| | | `------- CRC check / data error
| | `-------- diskette controller failure
| `--------- seek to track failed
`---------- diskette time-out
40:42 7 bytes NEC diskette controller status (see FDC)
40:49 byte Current video mode (see VIDEO MODE)
40:4A word Number of screen columns
40:4C word Size of current video regen buffer in bytes
40:4E word Offset of current video page in video regen buffer
40:50 8 words Cursor position of pages 1-8, high order byte=row
low order byte=column; changing this data isn't
reflected immediately on the display
40:60 byte Cursor ending (bottom) scan line (don't modify)
40:61 byte Cursor starting (top) scan line (don't modify)
40:62 byte Active display page number
40:63 word Base port address for active 6845 CRT controller
3B4h = mono, 3D4h = color
40:65 byte 6845 CRT mode control register value (port 3x8h)
EGA/VGA values emulate those of the MDA/CGA
40:66 byte CGA current color palette mask setting (port 3d9h)
EGA and VGA values emulate the CGA
40:67 dword CS:IP for 286 return from protected mode
dword Temp storage for SS:SP during shutdown
dword Day counter on all products after AT
dword PS/2 Pointer to reset code with memory preserved
5 bytes Cassette tape control (before AT)
40:6C dword Daily timer counter, equal to zero at midnight;
incremented by INT 8; read/set by INT 1A
40:70 byte Clock rollover flag, set when 40:6C exceeds 24hrs
40:71 byte BIOS break flag, bit 7 is set if Ctrl-Break was
*ever* hit; set by INT 9
40:72 word Soft reset flag via Ctl-Alt-Del or JMP FFFF:0
1234h Bypass memory tests & CRT initialization
4321h Preserve memory
5678h System suspend
9ABCh Manufacturer test
ABCDh Convertible POST loop
????h many other values are used during POST
40:74 byte Status of last hard disk operation (see INT 13,1)
40:75 byte Number of hard disks attached
40:76 byte XT fixed disk drive control byte
40:77 byte Port offset to current fixed disk adapter
40:78 4 bytes Time-Out value for LPT1,LPT2,LPT3(,LPT4 except PS/2)
40:7C 4 bytes Time-Out value for COM1,COM2,COM3,COM4
40:80 word Keyboard buffer start offset (seg=40h,BIOS 10-27-82)
40:82 word Keyboard buffer end offset (seg=40h,BIOS 10-27-82)
40:84 byte Rows on the screen (less 1, EGA)
40:85 word Point height of character matrix (EGA)
byte PCjr: character to be repeated if the typematic
repeat key takes effect
40:86 byte PCjr: initial delay before repeat key action begins
40:87 byte PCjr: current Fn function key number
byte Video mode options (EGA)
|7|6|5|4|3|2|1|0| Video mode options (EGA)
| | | | | | | `-- 1=alphanumeric cursor emulation enabled
| | | | | | `--- 1=video subsystem attached to monochrome
| | | | | `---- reserved
| | | | `----- 1=video subsystem is inactive
| | | `------ reserved
| `--------- video RAM 00-64K 10-192K 01-128K 11-256K
`---------- video mode number passed to INT 10, function 0
40:88 byte PCjr: third keyboard status byte
EGA feature bit switches, emulated on VGA
|7|6|5|4|3|2|1|0| EGA feature bit switches (EGA)
| | | | | | | `-- EGA SW1 config (1=off)
| | | | | | `--- EGA SW2 config (1=off)
| | | | | `---- EGA SW3 config (1=off)
| | | | `----- EGA SW4 config (1=off)
| | | `------ Input FEAT0 (ISR0 bit 5) after output on FCR0
| | `------- Input FEAT0 (ISR0 bit 6) after output on FCR0
| `-------- Input FEAT1 (ISR0 bit 5) after output on FCR1
`--------- Input FEAT1 (ISR0 bit 6) after output on FCR1
40:89 byte Video display data area (MCGA and VGA)
|7|6|5|4|3|2|1|0| Video display data area (MCGA and VGA)
| | | | | | | `-- 1=VGA is active
| | | | | | `--- 1=gray scale is enabled
| | | | | `---- 1=using monochrome monitor
| | | | `----- 1=default palette loading is disabled
| | | `------ see table below
| | `------- reserved
| `-------- 1=display switching enabled
`--------- alphanumeric scan lines (see table below)
Bit7 Bit4 Scan Lines
0 0 350 line mode
0 1 400 line mode
1 0 200 line mode
1 1 reserved
40:8A byte Display Combination Code (DCC) table index (EGA)
40:8B byte Last diskette data rate selected
|7|6|5|4|3|2|1|0| last diskette data rate selected
| | | | `--------- reserved
| | `------------ last floppy drive step rate selected
`-------------- last floppy data rate selected
Data Rate Step Rate
00 500K bps 00 step rate time of 0C
01 300K bps 01 step rate time of 0D
10 250K bps 10 step rate time of 0A
11 reserved 11 reserved
40:8C byte Hard disk status returned by controller
40:8D byte Hard disk error returned by controller
40:8E byte Hard disk interrupt control flag(bit 7=working int)
40:8F byte Combination hard/floppy disk card when bit 0 set
40:90 4 bytes Drive 0,1,2,3 media state
|7|6|5|4|3|2|1|0| drive media state (4 copies)
| | | | | `------- drive/media state (see below)
| | | | `------- reserved
| | | `------- 1=media/drive established
| | `------- double stepping required
`--------- data rate: 00=500K bps 01=300K bps
10=250K bps 11=reserved
Bits
210 Drive Media State
000 360Kb diskette/360Kb drive not established
001 360Kb diskette/1.2Mb drive not established
010 1.2Mb diskette/1.2Mb drive not established
011 360Kb diskette/360Kb drive established
100 360Kb diskette/1.2Mb drive established
101 1.2Mb diskette/1.2Mb drive established
110 Reserved
111 None of the above
40:94 byte Track currently seeked to on drive 0
40:95 byte Track currently seeked to on drive 1
40:96 byte Keyboard mode/type
|7|6|5|4|3|2|1|0| Keyboard mode/type
| | | | | | | `--- last code was the E1 hidden code
| | | | | | `---- last code was the E0 hidden code
| | | | | `----- right CTRL key depressed
| | | | `------ right ALT key depressed
| | | `------- 101/102 enhanced keyboard installed
| | `-------- force num-lock if Rd ID & KBX
| `--------- last char was first ID char
`---------- read ID in process
40:97 byte Keyboard LED flags
|7|6|5|4|3|2|1|0| Keyboard LED flags
| | | | | | | `--- scroll lock indicator
| | | | | | `---- num-lock indicator
| | | | | `----- caps-lock indicator
| | | | `------ circus system indicator
| | | `------- ACK received
| | `-------- re-send received flag
| `--------- mode indicator update
`---------- keyboard transmit error flag
40:98 dword Pointer to user wait complete flag
40:9C dword User wait Time-Out value in microseconds
40:A0 byte RTC wait function flag
|7|6|5|4|3|2|1|0| INT 15,86 RTC wait function flag
| | | | | | | `--- 1= wait pending
| `-------------- not used
`--------------- 1=INT 15,86 wait time elapsed
40:A1 byte LANA DMA channel flags
40:A2 2 bytes Status of LANA 0,1
40:A4 dword Saved hard disk interrupt vector
40:A8 dword BIOS Video Save/Override Pointer Table address
(see VIDEO TABLES)
40:AC 8 bytes Reserved
40:B4 byte Keyboard NMI control flags (convertible)
40:B5 dword Keyboard break pending flags (convertible)
40:B9 byte Port 60 single byte queue (convertible)
40:BA byte Scan code of last key (convertible)
40:BB byte NMI buffer head pointer (convertible)
40:BC byte NMI buffer tail pointer (convertible)
40:BD 16bytes NMI scan code buffer (convertible)
40:CE word Day counter (convertible and after)
40:F0 16bytes Intra-Applications Communications Area (IBM Technical
Reference incorrectly locates this at 50:F0-50:FF)
Address Size Description (BIOS/DOS Data Area)
50:00 byte Print screen status byte
00 = PrtSc not active,
01 = PrtSc in progress
FF = error
50:01 3 bytes Used by BASIC
50:04 byte DOS single diskette mode flag, 0=A:, 1=B:
50:05 10bytes POST work area
50:0F byte BASIC shell flag; set to 2 if current shell
50:10 word BASICs default DS value (DEF SEG)
50:12 dword Pointer to BASIC INT 1C interrupt handler
50:16 dword Pointer to BASIC INT 23 interrupt handler
50:1A dword Pointer to BASIC INT 24 disk error handler
50:20 word DOS dynamic storage
50:22 14bytes DOS diskette initialization table (INT 1E)
50:30 4bytes MODE command
70:00 I/O drivers from IO.SYS/IBMBIO.COM
The following map varies in size and locus
07C0:0 Boot code is loaded here at startup (31k mark)
A000:0 EGA/VGA RAM for graphics display mode 0Dh & above
B000:0 MDA RAM, Hercules graphics display RAM
B800:0 CGA display RAM
C000:0 EGA/VGA BIOS ROM (thru C7FF)
C400:0 Video adapter ROM space
C600:0 256bytes PGA communication area
C800:0 16K Hard disk adapter BIOS ROM
C800:5 XT Hard disk ROM format, AH=Drive, AL=Interleave
D000:0 32K Cluster adapter BIOS ROM
D800:0 PCjr conventionalsoftware cartridge address
E000:0 64K Expansion ROM space (hardwired on AT)
128K PS/2 System ROM (thru F000)
F000:0 System monitor ROM
PCjr: software cartridge override address
F400:0 System expansion ROMs
F600:0 IBM ROM BASIC (AT)
F800:0 PCjr software cartridge override address
FC00:0 BIOS ROM
FF00:0 System ROM
FFA6:E ROM graphics character table
FFFF:0 ROM bootstrap code
FFFF:5 8 bytes ROM date (not applicable for all clones)
FFFF:E byte ROM machine id (see MACHINE ID)
Reference
http://docs.huihoo.com/help-pc/index.html
標籤:
IA32 相關基礎知識
星期四, 5月 08, 2008
DIY~~Dump BIOS code
今天幫同事寫了一個Dump BIOS code的程式在Vista下去把BIOS code dump 出來,雖然是一個很簡單的程式但是卻出現一些小問題啦!
目前我是透過VB6去繪製畫面,然後透過C撰寫的IO.DLL與IO.SYS來存取4G頂端記憶體位址線的內容,由於VB每次存取時都是4Bytes 為單位,然後我又會去更新畫面,因此Dump 2MB大小的BIOS要花掉好幾分鐘的時間 ...光是看到就傻眼了!
不過目前還沒去解決這個問題,因為懶的去改C的部份,不過也算是一種體驗啦!
因為沒實做過都不知道自己會遇到什麼問題,呵呵!!!

目前我是透過VB6去繪製畫面,然後透過C撰寫的IO.DLL與IO.SYS來存取4G頂端記憶體位址線的內容,由於VB每次存取時都是4Bytes 為單位,然後我又會去更新畫面,因此Dump 2MB大小的BIOS要花掉好幾分鐘的時間 ...光是看到就傻眼了!
不過目前還沒去解決這個問題,因為懶的去改C的部份,不過也算是一種體驗啦!
因為沒實做過都不知道自己會遇到什麼問題,呵呵!!!
或許你會問我說BIOS廠商不是提供WinFlash可以去Dump了嗎? 幹麻還自己搞一個,因為多點選擇嘛! (DOS下的還沒寫,找個時間在寫一下 >.<) 而且我目前拿到的P廠商WinFlash還有問題,還沒辦法做這部份的動作,所以就自己DIY囉~~
可能你還會問我說Dump出來幹麻? 因為我要拿來比對BIOS 啦,由於有些設定BIOS是開機後才會回寫回去BIOS ROM,所以進入OS後把BIOS傾印出來後比對原來燒進去的BIOS,這樣子就可以知道在Runtime過程中BIOS回寫了哪些東西回去BIOS ROM(因為遇到DMI字串找不到的問題,所以比對一下目前BIOS是放在哪邊)。
標籤:
Windows 程式相關
星期三, 5月 07, 2008
PowerCfg 工具
這邊介紹一下有關Vista Power Management 的工具,這是內建在Vista裡面的工具(cmd中直接鍵入powercfg就可以用了),在微軟的網站也可以找到相關白皮書裡面有很清楚的描述與用法說明。
會使用到這工具是因為在看一個奇怪的問題,而這個問題描述如下:
1.設定S4 : 15分鐘後進入
2.設定Scheduled Task (隨便設定一個,然後等個幾秒後使用RTC wakeup)
3.手動進入S3 (開始->S3)
4.時間到達,系統使用RTC wakeup (此時螢幕不會點亮,因為是系統規定的)
5.此時不要產生任何event (不要碰系統)
6.等兩分鐘後,系統會自動進入S3 (Vista的設計,見Note#1)
7.等15分鐘後,系統會wakeup,然後進入S4 #Problem (見Note#2)
我的問題是在步驟7,因為同樣的步驟在XP不會再進入S4而Vista會,因此查詢相關SPEC的過程中發現了這個工具。
這個工具可以去查看我們在電源選項中的設定,包含你要幾分鐘後關閉LCD..等,你可能會問我說直接在電源選項畫面設定不就看的到了,幹麻還用這個工具看,原因是因為電源選項中的每個選項都有一個GUID,每個GUID都有其代表的意義,這個意義在微軟的白皮書中有定義,所以你要去對照著看,因此才會需要用這個工具。
使用方式在微軟白皮書上都有說明,這邊就描述我去Dump的方式:
powercfg -getactivescheme (查看目前選用的電源管理的GUID)
powercfg -q 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c > T.log (查詢內容)
上面一串GUID不一定會ㄧ樣,看是GUID中的Sub-Guid就會跟白皮書上面定義的一樣,因此把它Dump到一個檔案中後你就可以對照著看了(T.log)。
Note#1 Vista Energy Conservarion 這份文件內的描述有提到Vista為什麼等兩分鐘後自動進入S3: Improved idle detection that helps ensure that a PC awakened from the network or for scheduled activity returns to Sleep after 2 minutes of idleness.
Note#2 Power Management Policy(PMPolicy_Vista.docx)這份文件中有提到如果設定哪個欄位後,Vista會從S3 wakeup然後自動進入S4:
Hibernate Idle Timeout Setting (GUID: 9d7815a6-7ee4-497e-8888-515a05f02364): Duration of time after Sleep that the system automatically wakes and enters Hibernate.
Reference
www.microsoft.com/taiwan/whdc/system/pnppwr/powermgmt
會使用到這工具是因為在看一個奇怪的問題,而這個問題描述如下:
1.設定S4 : 15分鐘後進入
2.設定Scheduled Task (隨便設定一個,然後等個幾秒後使用RTC wakeup)
3.手動進入S3 (開始->S3)
4.時間到達,系統使用RTC wakeup (此時螢幕不會點亮,因為是系統規定的)
5.此時不要產生任何event (不要碰系統)
6.等兩分鐘後,系統會自動進入S3 (Vista的設計,見Note#1)
7.等15分鐘後,系統會wakeup,然後進入S4 #Problem (見Note#2)
我的問題是在步驟7,因為同樣的步驟在XP不會再進入S4而Vista會,因此查詢相關SPEC的過程中發現了這個工具。
這個工具可以去查看我們在電源選項中的設定,包含你要幾分鐘後關閉LCD..等,你可能會問我說直接在電源選項畫面設定不就看的到了,幹麻還用這個工具看,原因是因為電源選項中的每個選項都有一個GUID,每個GUID都有其代表的意義,這個意義在微軟的白皮書中有定義,所以你要去對照著看,因此才會需要用這個工具。
使用方式在微軟白皮書上都有說明,這邊就描述我去Dump的方式:
powercfg -getactivescheme (查看目前選用的電源管理的GUID)
powercfg -q 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c > T.log (查詢內容)
上面一串GUID不一定會ㄧ樣,看是GUID中的Sub-Guid就會跟白皮書上面定義的一樣,因此把它Dump到一個檔案中後你就可以對照著看了(T.log)。
Note#1 Vista Energy Conservarion 這份文件內的描述有提到Vista為什麼等兩分鐘後自動進入S3: Improved idle detection that helps ensure that a PC awakened from the network or for scheduled activity returns to Sleep after 2 minutes of idleness.
Note#2 Power Management Policy(PMPolicy_Vista.docx)這份文件中有提到如果設定哪個欄位後,Vista會從S3 wakeup然後自動進入S4:
Hibernate Idle Timeout Setting (GUID: 9d7815a6-7ee4-497e-8888-515a05f02364): Duration of time after Sleep that the system automatically wakes and enters Hibernate.
Reference
www.microsoft.com/taiwan/whdc/system/pnppwr/powermgmt
標籤:
IA32 相關基礎知識
星期五, 5月 02, 2008
WinDbg 查看Log
最近拿WinDbg查看一些藍底白字的Log,順便做一下筆記:
ㄧ般藍屏看到下面的描述如下:
STOP : 0x000000D1 (0x00000080 , 0x0000001d , 0x00000001,0x83c74674)
當Dumpfile從WinDbg中開啟並查看所看到的描述如下:
DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) <--錯誤代碼
Arg1: 00000080, memory referenced <--參考的記憶體位址
Arg2: 0000001d, IRQL <--目前的IRQL
Arg3: 00000001, value 0 = read operation, 1 = write operation <--讀/寫發生問題
Arg4: 83c74674, address which referenced memory <--有問題的Code的記憶體位址
從下面範例可以得知,記憶體位址83c74674h的地方是要把EAX值寫入到某個記憶體位址中,而這個記憶體位址在0x0023:0x00000080的地方,而寫入時發生錯誤:
83c74674 0100 add dword ptr [eax],eax ds:0023:00000080=????????
另外還可以看到下面的描述:
FOLLOWUP_IP: mssmbios!SMBiosACPIProcessACPIData+f2
8ce6b6f0 85c0 test eax,eax
結論1: 看起來是mssmbios.sys 出錯,錯誤的原因可能是ACPI code的寫入問題,所以要查看看BIOS是否有去動態更新ACPI table或是ACPI 出錯而造成這個藍屏。
另一個案例
SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
Arg1: c0000005, The exception code that was not handled
Arg2: fac41750, The address that the exception occurred at
Arg3: fafb4430, Exception Record Address
Arg4: fafb 412c , Context Record Address
IMAGE_NAME: intelppm.sys
fac41750 0f 32 rdmsr
結論2:看樣子是RDMSR造成的問題。
使用WinDbg開啟Dump file的方式如下:


開啟後鍵入!analyze -v ,就可以查看相關資訊,另外要注意的事情是要安裝好symbol files,相關的WinDbg指令/安裝/設定方式請參考微軟網站說明。
Reference
微軟網站
ㄧ般藍屏看到下面的描述如下:
STOP : 0x000000D1 (0x00000080 , 0x0000001d , 0x00000001,0x83c74674)
當Dumpfile從WinDbg中開啟並查看所看到的描述如下:
DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) <--錯誤代碼
Arg1: 00000080, memory referenced <--參考的記憶體位址
Arg2: 0000001d, IRQL <--目前的IRQL
Arg3: 00000001, value 0 = read operation, 1 = write operation <--讀/寫發生問題
Arg4: 83c74674, address which referenced memory <--有問題的Code的記憶體位址
從下面範例可以得知,記憶體位址83c74674h的地方是要把EAX值寫入到某個記憶體位址中,而這個記憶體位址在0x0023:0x00000080的地方,而寫入時發生錯誤:
83c74674 0100 add dword ptr [eax],eax ds:0023:00000080=????????
另外還可以看到下面的描述:
FOLLOWUP_IP: mssmbios!SMBiosACPIProcessACPIData+f2
8ce6b6f0 85c0 test eax,eax
結論1: 看起來是mssmbios.sys 出錯,錯誤的原因可能是ACPI code的寫入問題,所以要查看看BIOS是否有去動態更新ACPI table或是ACPI 出錯而造成這個藍屏。
另一個案例
SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
Arg1: c0000005, The exception code that was not handled
Arg2: fac41750, The address that the exception occurred at
Arg3: fafb4430, Exception Record Address
Arg4: fafb 412c , Context Record Address
IMAGE_NAME: intelppm.sys
fac41750 0f 32 rdmsr
結論2:看樣子是RDMSR造成的問題。
使用WinDbg開啟Dump file的方式如下:
開啟後鍵入!analyze -v ,就可以查看相關資訊,另外要注意的事情是要安裝好symbol files,相關的WinDbg指令/安裝/設定方式請參考微軟網站說明。
Reference
微軟網站
標籤:
IA32 相關基礎知識
星期三, 4月 30, 2008
S3/S4 測試工具開發
源由:
前幾個星期為了解一個VS Mode (設定1分鐘後關閉螢幕) bug 所以自己寫了一個Win32工具去檢查CMOS RTC alarm 和RTC interrupt 的設定值還有監控RTC Enable bit設定值(PMBase),而這個問題的徵狀是當系統從S4 Resume後,等個10秒後就會看到螢幕被關閉。
追蹤後發現這應該是Vista的計時器的問題,他所謂的一分鐘是指"當OS沒收到任何event後開始計時",所以當進入S4的時候計時器可能已經跑了35秒,而當系統從S4 Resume後計時器會繼續計時,因此等個10幾秒就進入VS mode了。
會被開這條Bug是因為開Bug的人認為計時器應該重新計算,所以參考了一些其他機種做法後決定,使用相同的解決方式去解決(Notify Power button)這個問題。
而在此時我們的T學長看到我個工具,因此問我說有沒有辦法寫一個自動進入S3/S4且可以定時wakeup的工具...
原本在Vista底下就已經有工具可以測試,而我們的客戶也有撰寫一個工具也可達到這個功能,另外ALi也有一個類似的工具也做的到這個功能,因此是有機會可以自行開發出來這個工具。
實驗ㄧ過程:
原先我想的很單純,在BIOS角度就是去設定好RTC alarm時間,然後去改變RTC Enable bit,接著呼叫API讓系統進入S3/S4就應該可以了,不過實驗後發現OS會把RTC Enable 清除,所以就算我設定了也沒有用 >.<
實驗二過程:
秉持著研究的精神,所以我認為OS會去清除RTC enable bit就代表OS才能決定這個bit的狀態,我沒辦法透過Ring 0層的AP直接去修改暫存器值,因此他ㄧ定有方式去控制; 查詢了相關資訊後發現有API可以做這些事情,因此問題就只是在如何用這些API而已。
結論:
經過實驗過後,這些API真的可以達到我需要的功能,所以也只能說Windows真的管很多,想要偷偷修改暫存器都不行, 呵呵!
相關的API:
CreateWaitableTimer
SetWaitableTimer
SetSuspendState
WaitForSingleObject
CancelWaitableTimer
CloseHandle
隨便寫的程式,所以畫面看起來很難看 ^^!
Reference
Microsoft 網站
標籤:
Windows 程式相關
星期三, 4月 16, 2008
Scratchpad Data Register
今天看MCH Spec看到一個有趣的暫存器叫做 SKPD--Scratchpad Data Register ,因為實在是很有趣的一個東西所以自己就寫下筆記來紀錄一下。
這個暫存器的屬性是R/W,而他的說明是可以用來儲存資料的一個暫存器,長度要看Chipset,有些是16 bits 也有些是32 bits。
那這個東西是幹麻的呢? 嗯...Spec上沒說明清楚,不過我自己查了一些資料以及比較了一些用法,發現這個暫存器可以給 【任何人使用】,且"Platform reset"後"可能"不會被清除資料。
簡單的說就是任何人任何程式碼都可以把一些想要紀錄的資訊往這個暫存器去紀錄,至於寫進去的值是代表什麼意思就只有寫的人知道。
目前看到應用的時機有3個:
1. Memory init 後可以利用他儲存一些狀態值,然後給下一次開機時檢查
2. 紀錄是否是Warm boot ,例如你可以在某個點去設定這個暫存器,然後在FFFF_FFF0一進去的點去判斷,假如此暫存器不為0 則在做一次CF9h 的Full reset,以避免一些問題。
3. ME Driver
以上都是自己猜測的,所以實際的用法還是要請教懂的人啦~~呵呵!
Reference
www.google.com
www.Intel.com
這個暫存器的屬性是R/W,而他的說明是可以用來儲存資料的一個暫存器,長度要看Chipset,有些是16 bits 也有些是32 bits。
那這個東西是幹麻的呢? 嗯...Spec上沒說明清楚,不過我自己查了一些資料以及比較了一些用法,發現這個暫存器可以給 【任何人使用】,且"Platform reset"後"可能"不會被清除資料。
簡單的說就是任何人任何程式碼都可以把一些想要紀錄的資訊往這個暫存器去紀錄,至於寫進去的值是代表什麼意思就只有寫的人知道。
目前看到應用的時機有3個:
1. Memory init 後可以利用他儲存一些狀態值,然後給下一次開機時檢查
2. 紀錄是否是Warm boot ,例如你可以在某個點去設定這個暫存器,然後在FFFF_FFF0一進去的點去判斷,假如此暫存器不為0 則在做一次CF9h 的Full reset,以避免一些問題。
3. ME Driver
以上都是自己猜測的,所以實際的用法還是要請教懂的人啦~~呵呵!
Reference
www.google.com
www.Intel.com
標籤:
IA32 相關基礎知識
星期四, 4月 10, 2008
Karnaugh Minimizer
卡諾圖化簡工具Karnaugh Minimizer
最近忙著解一堆Hdd password feature bugs , 幾乎都是一些Password state判斷式的問題,雖然是剛換新的廠商,也是接觸到新的bios code,但是裡面的問題也太多了吧 >.<
而目前遇到的一堆問題幾乎都是沒把相關測試條件考慮完整所造成,只是沒想到我竟然還畫起了卡諾圖來幫忙解決問題...記得上一次畫卡諾圖已經是好幾年前還在念二專的事情了,只是沒想到解Bios bug也會在拿出來用.
因為目前需要判斷的條件有很多個,因此在畫卡諾圖的變數多達6~8個,光是化解就花了我不少時間,因此秉持著Time is money的精神,所以又在一次從Google大神中找到一些工具來輔助...(講白一點叫做偷懶)
目前測試了幾個Google大神找到的工具,有些只能支援到4x4,有些能支援到更多,但是化解的結果也不一定正確(果然還是要自己動手化解一次),而目前找到了一個比較穩定的版本是Karnaugh Minimizer 最新版有出到了v2.0 , 有興趣的朋友可以參考看看。
Reference
Karnaugh map minimizing
Karnaugh Minimizer
Karnaugh Minimizer 1.2 <--只支援到4x4
工具 b...ng
最近忙著解一堆Hdd password feature bugs , 幾乎都是一些Password state判斷式的問題,雖然是剛換新的廠商,也是接觸到新的bios code,但是裡面的問題也太多了吧 >.<
而目前遇到的一堆問題幾乎都是沒把相關測試條件考慮完整所造成,只是沒想到我竟然還畫起了卡諾圖來幫忙解決問題...記得上一次畫卡諾圖已經是好幾年前還在念二專的事情了,只是沒想到解Bios bug也會在拿出來用.
因為目前需要判斷的條件有很多個,因此在畫卡諾圖的變數多達6~8個,光是化解就花了我不少時間,因此秉持著Time is money的精神,所以又在一次從Google大神中找到一些工具來輔助...(講白一點叫做偷懶)
目前測試了幾個Google大神找到的工具,有些只能支援到4x4,有些能支援到更多,但是化解的結果也不一定正確(果然還是要自己動手化解一次),而目前找到了一個比較穩定的版本是Karnaugh Minimizer 最新版有出到了v2.0 , 有興趣的朋友可以參考看看。
Reference
Karnaugh map minimizing
Karnaugh Minimizer
Karnaugh Minimizer 1.2 <--只支援到4x4
工具 b...ng
星期四, 3月 20, 2008
ACPI BIOS & Bluescreen
ACPI BIOS造成的BlueScreen 可能的原因有很多,自己整理了幾個地方。
EC: Check EC code
_INI : Check _INI code
MCFG Table : Report Range through MCFG. ACPI table defined in PCI Firmware Spec v3.0.
如果有改變PCIExpress bar or MCHBar...等
Motherboard.asl : Check System Resource allocate (ex: PCIEBAR address/MCHBar address...)
DCK_CAP : Defined in FACP Table. 如果你有定義Docking,但是沒Enable Support bit.
可以檢查ACPI BIOS造成的 Bluescreen 錯誤代碼的網址:
http://msdn2.microsoft.com/en-us/library/ms793993.aspx
Reference
Microsoft
EC: Check EC code
_INI : Check _INI code
MCFG Table : Report Range through MCFG. ACPI table defined in PCI Firmware Spec v3.0.
如果有改變PCIExpress bar or MCHBar...等
Motherboard.asl : Check System Resource allocate (ex: PCIEBAR address/MCHBar address...)
DCK_CAP : Defined in FACP Table. 如果你有定義Docking,但是沒Enable Support bit.
可以檢查ACPI BIOS造成的 Bluescreen 錯誤代碼的網址:
http://msdn2.microsoft.com/en-us/library/ms793993.aspx
Reference
Microsoft
星期一, 3月 10, 2008
有關規格書的相關資料
剛入門的時候,想找個資料都沒人告訴你要如何查,所以當初請教了以前的同事Sxxxk (打馬賽克),他目前服務在某家Chipset大廠,而俗稱"S" man的好朋友很熱心的告訴我ㄧ些相關書籍的知識~~~
因此我在剛入門的時候把他告訴我的ㄧ些相關資訊整理了一些筆記,而這些筆記只是大致上介紹一些入門的相關訊息,讓想要查閱資料的時候比較有個底。
其中查閱資料除了Chipset廠商網站上所提供的一些相關訊息外,你還可以找FAE去申請ㄧ些相關書籍,另外你還可以由Chipset廠商提供的帳號登入相關網站去搜尋你要的資料..等,底下就大致上整理了一下相關入門知識:
1.Chipset廠商ㄧ般網頁與權限登入的網頁(基於保密,所以請去教你們學長,不要問我):
OEM/OEM廠商會有權限帳號可以去Chipset vendor那邊申請紅/黃皮書。
2.技術手冊分級
紅皮書 RCW(Red Cover Webside):
Chipset剛開發出來的技術規格書。
一般都是Chipset 廠商內部使用,BIOS端也可以透過。
黃皮書 YCW:
Chipset 成熟後的規格書。
一般給合作廠商使用。
白皮書 WCW:
Chipset 可公開給所有廠商使用的規格書。
一般網路上可以搜尋到的資料。
3. 每種技術手冊又分兩種類型:
PDG(Platform Design Guide):
說明線路如何拉,零件要放哪個位置,屬於硬體拉線的Spec。
EDS(External Design Specification):
屬於應用層的技術文件。
說明哪一支接腳代表的意義,接腳要接到那ㄧ個位置。
還說明內部暫存器的特性說明,一般BIOS會看這一本。
~以上是個人小筆記,如有誤請不吝指正~
因此我在剛入門的時候把他告訴我的ㄧ些相關資訊整理了一些筆記,而這些筆記只是大致上介紹一些入門的相關訊息,讓想要查閱資料的時候比較有個底。
其中查閱資料除了Chipset廠商網站上所提供的一些相關訊息外,你還可以找FAE去申請ㄧ些相關書籍,另外你還可以由Chipset廠商提供的帳號登入相關網站去搜尋你要的資料..等,底下就大致上整理了一下相關入門知識:
1.Chipset廠商ㄧ般網頁與權限登入的網頁(基於保密,所以請去教你們學長,不要問我):
OEM/OEM廠商會有權限帳號可以去Chipset vendor那邊申請紅/黃皮書。
2.技術手冊分級
紅皮書 RCW(Red Cover Webside):
Chipset剛開發出來的技術規格書。
一般都是Chipset 廠商內部使用,BIOS端也可以透過。
黃皮書 YCW:
Chipset 成熟後的規格書。
一般給合作廠商使用。
白皮書 WCW:
Chipset 可公開給所有廠商使用的規格書。
一般網路上可以搜尋到的資料。
3. 每種技術手冊又分兩種類型:
PDG(Platform Design Guide):
說明線路如何拉,零件要放哪個位置,屬於硬體拉線的Spec。
EDS(External Design Specification):
屬於應用層的技術文件。
說明哪一支接腳代表的意義,接腳要接到那ㄧ個位置。
還說明內部暫存器的特性說明,一般BIOS會看這一本。
~以上是個人小筆記,如有誤請不吝指正~
星期四, 2月 28, 2008
Keyboard Test
這是以前在寫測試程式時留下來的小作品,用C語言撰寫的。
原理是利用C語言所提供的函數去替換掉IRQ中斷服務程式,然後指向自己的函數並且自己處理Scan code。
在此程式中主要是給產線測試用,因此會顯示此按鍵是否已經測試過,有興趣的可以下載回去看看。
點我下載
原理是利用C語言所提供的函數去替換掉IRQ中斷服務程式,然後指向自己的函數並且自己處理Scan code。
在此程式中主要是給產線測試用,因此會顯示此按鍵是否已經測試過,有興趣的可以下載回去看看。
點我下載
星期四, 1月 24, 2008
2MB SPI Flash Part
這幾天為了換2MB 的SPI Flash part 真的有夠緊張的,因為急著要給產線使用,因此要在3天內把BIOS code porting 好,今天剛好把code給改好了,所以順便留下筆記給自己以後參考。
檢查項目:
1. ICH 能不能把Cycle 轉送到SPI/LPC ,預設是PCI
2.ICH 轉送的位址範圍是否支援到2MB
預設為PCI時,CPU cycle會轉送到 PCI Bus從4G頂端往下 4MB,如果改成轉送到 SPI/LPC時,需設定D0/D8暫存器,並且選擇哪一個Range需要被轉送到LPC/SPI 介面 (即BIOS Size,或Mapping 大小)。
3.EC 是否能支援到2MB ,華x 的EC chip需設定其內部暫存器,一共3個,分別是:
(1) 控制BIOS size大小的暫存器(i386 mode)
(2) SPI 暫存器 (告知EC底下的SPI Flash Part的大小)
(3)??? 暫存器(忘記叫啥名稱了,設定值需要跟BIOS size設定的一樣)
4. 目前是使用SPI cmd去Write/Erase ,但是讀取的時候是使用mapping方式,也就是直接存取線性位址內的資料就可以讀取到BIOS ROM內的資料(其他的就是HW動作做掉,當CPU讀取線性位址時,會把位址轉給LPC介面下的EC,EC內的LPC 介面會有SHM介面,此介面會把此位址訊號轉成SPI實體位址,並透過SPI Controller將資料讀取出來,所以這部份是EC支援),除了這個方式外,還可以自己撰寫SPIRead() routine,不過一般BIOS從Power on開始,這個Routine都還不能執行,因此Power on後,都是EC負責把BIOS ROM資料Mapping 到線性位址。
ex:
線性位址方式讀取BIOS ROM資料 : Memcpy (buffer , address , size);
SPI cmd方式讀取BIOS ROM資料 : SPIRead(buffer,address,size);
void SPIRead(...)
{
SPITransfer(OPCODE=Read , buffer , address,size);
}
檢查項目:
1. ICH 能不能把Cycle 轉送到SPI/LPC ,預設是PCI
2.ICH 轉送的位址範圍是否支援到2MB
預設為PCI時,CPU cycle會轉送到 PCI Bus從4G頂端往下 4MB,如果改成轉送到 SPI/LPC時,需設定D0/D8暫存器,並且選擇哪一個Range需要被轉送到LPC/SPI 介面 (即BIOS Size,或Mapping 大小)。
3.EC 是否能支援到2MB ,華x 的EC chip需設定其內部暫存器,一共3個,分別是:
(1) 控制BIOS size大小的暫存器(i386 mode)
(2) SPI 暫存器 (告知EC底下的SPI Flash Part的大小)
(3)??? 暫存器(忘記叫啥名稱了,設定值需要跟BIOS size設定的一樣)
4. 目前是使用SPI cmd去Write/Erase ,但是讀取的時候是使用mapping方式,也就是直接存取線性位址內的資料就可以讀取到BIOS ROM內的資料(其他的就是HW動作做掉,當CPU讀取線性位址時,會把位址轉給LPC介面下的EC,EC內的LPC 介面會有SHM介面,此介面會把此位址訊號轉成SPI實體位址,並透過SPI Controller將資料讀取出來,所以這部份是EC支援),除了這個方式外,還可以自己撰寫SPIRead() routine,不過一般BIOS從Power on開始,這個Routine都還不能執行,因此Power on後,都是EC負責把BIOS ROM資料Mapping 到線性位址。
ex:
線性位址方式讀取BIOS ROM資料 : Memcpy (buffer , address , size);
SPI cmd方式讀取BIOS ROM資料 : SPIRead(buffer,address,size);
void SPIRead(...)
{
SPITransfer(OPCODE=Read , buffer , address,size);
}
星期一, 1月 21, 2008
EFI ㄧ些小筆記
紀錄一些EFI中有關Firmware Device 內的專有名詞的解釋。
如下圖所示,這是EFI 模組化後在Firmware Device 內擺放一些模組化的範例圖:

其中:
1.FD=Firmware Device,他是一個實體的物體容器,用來儲存EFI code以及一些資料。
2.FV=Firmware volume ,卷,他是類似檔案系統的一種管理方式。
1 個FD中可以有很多個 FV
3.ㄧ般常見的FV :
(a) 儲存EFI code,你的BIOS Code可能會分成好幾個不同的FV
(b) 非揮發性資料,像是一些NV Store 變數、config 文件...等。
4. FFS = Firmware File System ,每一個FV都遵循這種檔案格式。
1 個FV 內可以有很多個FFS。
5. Section = 每一個FFS內還可以分成不同的Section。
FD > FV > FFS > Section
Reference
www.intel.com
如下圖所示,這是EFI 模組化後在Firmware Device 內擺放一些模組化的範例圖:
其中:
1.FD=Firmware Device,他是一個實體的物體容器,用來儲存EFI code以及一些資料。
2.FV=Firmware volume ,卷,他是類似檔案系統的一種管理方式。
1 個FD中可以有很多個 FV
3.ㄧ般常見的FV :
(a) 儲存EFI code,你的BIOS Code可能會分成好幾個不同的FV
(b) 非揮發性資料,像是一些NV Store 變數、config 文件...等。
4. FFS = Firmware File System ,每一個FV都遵循這種檔案格式。
1 個FV 內可以有很多個FFS。
5. Section = 每一個FFS內還可以分成不同的Section。
FD > FV > FFS > Section
Reference
www.intel.com
標籤:
EFI BIOS相關知識
A20 Gate v.s A20 Mask
前面文章中有提到A20的一些相關資訊,這邊我就畫一張圖來描述清楚一些概念。
對於圖中我們要區分的是A20 Gate與A20 Mask這兩種不同名詞分別所代表的意義為何。
以下是我自己畫的圖:
對於圖中我們要區分的是A20 Gate與A20 Mask這兩種不同名詞分別所代表的意義為何。
以下是我自己畫的圖:
這邊描述幾個相關的硬體介面電路所代表的意義: 上圖中可以看到有一個A20 Gate (OR 邏輯匣),他分別有兩支source pin,分別連接到南僑與KBC,且分別由Port 92h與KBC控制狀態,另外還有一支輸出pin連接到CPU的A20 Mask接腳。
A20M # 的由來:
A20 Gate: 一個可以用軟體控制的邏輯匣(AND/OR)...以前A20 gate 輸出腳是接到A20位址線(AND匣,其中一支src pin是接到KBC),後來改接到如上圖的 CPU A20M# 後變成OR匣 (這邊我不確定是否正確,因為我來不及參與過去^^)
A20 Gate 只針對A20有影響,對於其他的A21~A31都沒影響。
補充資料:
我曾經看過某個EC Datasheet,裡面有提到有關Port 92h的相關敘述,由於我並不是EC Engineer ,所以只能想像一下可能的實體電路圖:
如果你選擇EC內的Port 92h功能時,從圖中可以看見EC內部也有一個A20 Gate,而他的Source pin是跟KBC電路連接在一起,所以控制的方式會如同我前面畫的那張圖ㄧ樣的控制方式。
這部分補充資料是我自己想像所畫出來的圖,實際的電路圖還是要EC Engineer才能夠回答,所以僅供大家參考一下。
Reference
維基百科
標籤:
IA32 相關基礎知識
星期一, 12月 24, 2007
VC++ 與Windows Registry 註冊表
昨天因為工作需要寫了一個小工具去修正註冊表內的鍵值,所以自己留下一些筆記在部落格。
註冊表的存取方式由微軟文件上說明得知,需要做3種步驟:
1. 得到Handle
2. 存取你要的鍵值
3.關閉Handle
而步驟1中,最主要是透過RegCreateKey與RegOepnKey來得到Handle,而這兩種方式的不同點在於RegCreateKey會去搜尋子鍵是否存在,如果不存在時會建立一個新的子鍵,而另一個API則是找不到就找不到。
步驟2中,我們如果要去設定鍵值ㄧ般都會使用RegSetValueEx() 其中它裡面的參數有分成不同型態的鍵值,像是REG_DWORD、REG_SZ...etc,使用時需要步驟1 所得到的Handle。
步驟3中則是去關閉你開啟的Handle,因此這3個步驟必須合在一起做。
底下是我把這3個步驟整理成副程式,使用時直接呼叫就可以了:
1.SetRegValueBy_REG_DWORD();
2.SetRegValueBy_REG_SZ();
3. SetRegValueBy_REG_MULTI_SZ();
void SetRegValueBy_REG_DWORD(LPCSTR szKeyPath,LPCSTR szKeyName,DWORD *dwData)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");
if (RegSetValueEx(hk,
szKeyName,
0,
REG_DWORD,
(LPBYTE) dwData,
sizeof(DWORD)))
OutputDebugString("error!");
RegCloseKey(hk);
}
void SetRegValueBy_REG_SZ(LPCSTR szKeyPath,LPCSTR szKeyName,LPCSTR keyValue)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");
if (RegSetValueEx(hk,
szKeyName,
0,
REG_SZ,
(BYTE*)(LPCSTR) keyValue,
strlen(keyValue)))
OutputDebugString("error!");
RegCloseKey(hk);
}
void SetRegValueBy_REG_MULTI_SZ(LPCSTR szKeyPath,LPCSTR szKeyName,LPCSTR keyValue)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");
if (RegSetValueEx(hk,
szKeyName,
0,
REG_MULTI_SZ,
(BYTE*)(LPCSTR) keyValue,
strlen(keyValue)))
OutputDebugString("error!");
RegCloseKey(hk);
}
由副程式內可以得知,我是存取主鍵"HKEY_LOCAL_MACHINE"內的子鍵,所以如果要存取不同的主鍵時,要修改副程式內的主鍵。
底下是呼叫時的範例:
BOOL MyPatch()
{
LPCSTR szKeyPath1="SOFTWARE\\Microsoft\\WindowsNT\\MyTest";
LPCSTR szKeyName1="Label";
DWORD dwData=11;
SetRegValueBy_REG_DWORD(szKeyPath1,szKeyName1,&dwData);
return 0;
}
我Win32 的程式不好,雖然上面的程式碼可以用,但是如果有發現錯誤的地方,還是請大家幫忙指正並且告訴我~~~感恩喔!
註冊表的存取方式由微軟文件上說明得知,需要做3種步驟:
1. 得到Handle
2. 存取你要的鍵值
3.關閉Handle
而步驟1中,最主要是透過RegCreateKey與RegOepnKey來得到Handle,而這兩種方式的不同點在於RegCreateKey會去搜尋子鍵是否存在,如果不存在時會建立一個新的子鍵,而另一個API則是找不到就找不到。
步驟2中,我們如果要去設定鍵值ㄧ般都會使用RegSetValueEx() 其中它裡面的參數有分成不同型態的鍵值,像是REG_DWORD、REG_SZ...etc,使用時需要步驟1 所得到的Handle。
步驟3中則是去關閉你開啟的Handle,因此這3個步驟必須合在一起做。
底下是我把這3個步驟整理成副程式,使用時直接呼叫就可以了:
1.SetRegValueBy_REG_DWORD();
2.SetRegValueBy_REG_SZ();
3. SetRegValueBy_REG_MULTI_SZ();
void SetRegValueBy_REG_DWORD(LPCSTR szKeyPath,LPCSTR szKeyName,DWORD *dwData)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");
if (RegSetValueEx(hk,
szKeyName,
0,
REG_DWORD,
(LPBYTE) dwData,
sizeof(DWORD)))
OutputDebugString("error!");
RegCloseKey(hk);
}
void SetRegValueBy_REG_SZ(LPCSTR szKeyPath,LPCSTR szKeyName,LPCSTR keyValue)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");
if (RegSetValueEx(hk,
szKeyName,
0,
REG_SZ,
(BYTE*)(LPCSTR) keyValue,
strlen(keyValue)))
OutputDebugString("error!");
RegCloseKey(hk);
}
void SetRegValueBy_REG_MULTI_SZ(LPCSTR szKeyPath,LPCSTR szKeyName,LPCSTR keyValue)
{
HKEY hk;
if (RegCreateKey(HKEY_LOCAL_MACHINE,szKeyPath, &hk))
OutputDebugString("error!");
if (RegSetValueEx(hk,
szKeyName,
0,
REG_MULTI_SZ,
(BYTE*)(LPCSTR) keyValue,
strlen(keyValue)))
OutputDebugString("error!");
RegCloseKey(hk);
}
由副程式內可以得知,我是存取主鍵"HKEY_LOCAL_MACHINE"內的子鍵,所以如果要存取不同的主鍵時,要修改副程式內的主鍵。
底下是呼叫時的範例:
BOOL MyPatch()
{
LPCSTR szKeyPath1="SOFTWARE\\Microsoft\\WindowsNT\\MyTest";
LPCSTR szKeyName1="Label";
DWORD dwData=11;
SetRegValueBy_REG_DWORD(szKeyPath1,szKeyName1,&dwData);
return 0;
}
我Win32 的程式不好,雖然上面的程式碼可以用,但是如果有發現錯誤的地方,還是請大家幫忙指正並且告訴我~~~感恩喔!
標籤:
Windows 程式相關
星期四, 12月 20, 2007
A20 開關 v.s 回繞
很多剛入行的朋友問我A20開關的知識,我這邊就整理一下相關資訊,讓大家查閱的時候可以有個參考。
首先先說明相關的CPU的工作模式:在目前x86下面工作模式與A20有關的就是保護模式跟真實模式。
真實模式下,它允許定址到1MB記憶體,所以超過1MB的位址(FFFFFh)要繞回去00000h,這就是所謂的回繞。
保護模式下則分不同時間點來談,在80286 時,位址線增加到24 pin,所以可以定址到16M,而為了向下相容,所以設計了一個開關A20 Switch來控制A20~A23,當A20=0時,強制把位址線歸零,當A20=1時,可進位。
後來因為這個開關要Reset才能回復狀態,因此出現一個新的問題就是進入保護模式後,要重新開機才能回到真實模式。
於是有人就想說找一個設備,然後控制這個設備就可以做A20的開與關,因此找上了8042 KBC,所以以後開關A20 Switch時,只要去設定8042就可以了,因此解決了每次回真實模式都要重新開機的問題。
後來80386 之後,CPU的設計可以直接從保護模式切換回去真實模式,但是為了向下相容,所以還是一值保留這個設計。
慢慢的這個留下來的設計又出現新的問題,x86設計師可能想說每次都透過8042去開關速度有點慢,因此後來又提出了Fast A20 的設計,簡單說就是透過Port 92h 直接設定A20 switch開關。
至於這個被保留下來的設計,還有沒有當初的功能我也沒去測試,不過已經變成一種習慣,就是進入保護模式要去開關A20 switch。
以上大致上就是x86對於 A20的歷史,有興趣的人可以多去找找ㄧ些資料來看,或是做做小實驗,看看A20 switch不開的時候,會發生什麼事情 ^^.
首先先說明相關的CPU的工作模式:在目前x86下面工作模式與A20有關的就是保護模式跟真實模式。
真實模式下,它允許定址到1MB記憶體,所以超過1MB的位址(FFFFFh)要繞回去00000h,這就是所謂的回繞。
保護模式下則分不同時間點來談,在80286 時,位址線增加到24 pin,所以可以定址到16M,而為了向下相容,所以設計了一個開關A20 Switch來控制A20~A23,當A20=0時,強制把位址線歸零,當A20=1時,可進位。
後來因為這個開關要Reset才能回復狀態,因此出現一個新的問題就是進入保護模式後,要重新開機才能回到真實模式。
於是有人就想說找一個設備,然後控制這個設備就可以做A20的開與關,因此找上了8042 KBC,所以以後開關A20 Switch時,只要去設定8042就可以了,因此解決了每次回真實模式都要重新開機的問題。
後來80386 之後,CPU的設計可以直接從保護模式切換回去真實模式,但是為了向下相容,所以還是一值保留這個設計。
慢慢的這個留下來的設計又出現新的問題,x86設計師可能想說每次都透過8042去開關速度有點慢,因此後來又提出了Fast A20 的設計,簡單說就是透過Port 92h 直接設定A20 switch開關。
至於這個被保留下來的設計,還有沒有當初的功能我也沒去測試,不過已經變成一種習慣,就是進入保護模式要去開關A20 switch。
以上大致上就是x86對於 A20的歷史,有興趣的人可以多去找找ㄧ些資料來看,或是做做小實驗,看看A20 switch不開的時候,會發生什麼事情 ^^.
標籤:
IA32 相關基礎知識
星期三, 12月 19, 2007
純手工打造你自己的x86 BIOS(4)
上ㄧ篇文章我已經針對我的實驗做了敘述,這裡我就針對實際上我的程式碼撰寫的內容做一個介紹。
在程式碼的撰寫中,其實我只有使用了簡單的C語言跟組合語言語法,重點是要讓大家知道,其實BIOS跟一般的Boot Loader寫法沒什麼不同,只是PC上面的BIOS需要考慮的事情比一般的Boot Loader還多很多,因此程式碼 size可以大 到1MB甚至是2MB (ㄧ般Boot Loader不可能這麼大),所以我有機會玩一個這麼大的Boot Loader也真是很榮幸的啦!
廢話不多說,我就先針對我前面提到的Build.exe 內的程式碼說明;
底下是我的Build.c 內的程式碼片段,其實我就只有使用到fopen() 、fputc() ...等基本的函數去讀寫一個檔案,所以可以很容易的把我組譯好的MyBIOS.bin 跟EC.bin 塞進去同一個檔案內,做法其實很簡單,就是像我下面做法一樣,先利用fopen()開啟檔案,然後在把你要的資料寫進去檔案,只是寫的時候你要考慮file offset 位置的問題,因為當你燒錄到BIOS part中的時候,CPU是會固定重FFFF_FFF0h的位址讀取第一條指令,因此你要像我前面說的一樣,把MyBios.bin放在固定的位址中。
//建立一個空白的MyBIOS.ROM , 裡面資料都是00h
void show_help(void)
{
printf("Build.exe v1.0.0 by Harrison Hsieh \n");
printf("===========================================\n");
printf("/C Init MyBIOS.ROM \n");
printf("/B [EC] [BIOS] Add Rom \n");
printf("Output : MyBios.ROM \n");
}
void InitBiosROM(char *argv[])
{
FILE *fo;
long i;
if ((fo = fopen (BiosRom, "wb")) == (FILE *) NULL)
{
exit(1);
}
for(i=0 ; i<= BIOSSIZE ; i++) //1MB
{
fputc(0x00,fo);
}
/* All done, close the file */
fclose (fo);
}
在說明完Build.c內的做法後,接著說明MyBIOS.bin 內的程式碼撰寫;
其實在MyBios.asm 中,我只有做4 件事情:
1. 設定好FFFF_FFF0h的第一條指令
2.開啟BigReal Mode (因為我要設定ICH9的RCRB內的暫存器,所以要開啟)
3.設定ICH9內的暫存器,把所有Port 80h的訊號轉送到LPC介面(我的Post card走LPC界面,所以要設定)
4.輸出99h 到Port 80h(所以LPC介面上面的Post card就會顯示99h)
底下是我的MyBIOS.asm 內的程式碼片段:
COLDBOOT:
CLI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 1. Enable big real mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
JMPREG di,Make4GBSegmentDI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 2. Set RCRB base address
;; 3. Config ICH9 Register
;; 4. Out 99h to Port 80h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
....
mov dx, 0cfch
mov eax,RCRB_BaseAddr
out dx, eax
....
and BYTE PTR es:[esi], NOT (04h) ; RCRB+xxxxh bit 2=0 Output to LPC
....
fPostCode:
mov al,099h
mov dx,80h
out dx,al
jmp fPostCode ;無窮回圈ㄧ直顯示99h
...
...
wbinvd ; ...begins here on power up
PUBLIC POWER
POWER:
JMP COLDBOOT ; first jump
DB '11/14/07',00,00,00 ; My release marker
以上就是我撰寫的程式碼內容的說明,其實沒有用到什麼特別的東西,如果說比較難的部份大概就是如何把程式碼塞到正確的位址吧。
總結:
純手工打造你自己的x86 BIOS 文章(1)~(4) 在這邊就做一個結束,在這幾篇文章中的實驗我主要是要幫助剛入門的BIOS新手去了解整個BIOS vendor提供的BIOS環境架構以及實際上BIOS code撰寫的第一步,因為很多東西都是入門的第一步比較難。
還記得ㄧ年前我剛入行的時候,我們學長跟我說寫BIOS最簡單的方式就是自己把一個BIOS寫到能開機你大概就已經學會了,雖然我離能自己寫到開機還有一段距離,不過在學習的過程中也學到了很多東西,因此當初會想自己純手工寫一個能讓x86 CPU執行一段BIOS code的環境也是希望能幫助更多BIOS入門時遇到挫折的朋友 ^^Y。
在程式碼的撰寫中,其實我只有使用了簡單的C語言跟組合語言語法,重點是要讓大家知道,其實BIOS跟一般的Boot Loader寫法沒什麼不同,只是PC上面的BIOS需要考慮的事情比一般的Boot Loader還多很多,因此程式碼 size可以大 到1MB甚至是2MB (ㄧ般Boot Loader不可能這麼大),所以我有機會玩一個這麼大的Boot Loader也真是很榮幸的啦!
廢話不多說,我就先針對我前面提到的Build.exe 內的程式碼說明;
底下是我的Build.c 內的程式碼片段,其實我就只有使用到fopen() 、fputc() ...等基本的函數去讀寫一個檔案,所以可以很容易的把我組譯好的MyBIOS.bin 跟EC.bin 塞進去同一個檔案內,做法其實很簡單,就是像我下面做法一樣,先利用fopen()開啟檔案,然後在把你要的資料寫進去檔案,只是寫的時候你要考慮file offset 位置的問題,因為當你燒錄到BIOS part中的時候,CPU是會固定重FFFF_FFF0h的位址讀取第一條指令,因此你要像我前面說的一樣,把MyBios.bin放在固定的位址中。
//建立一個空白的MyBIOS.ROM , 裡面資料都是00h
void show_help(void)
{
printf("Build.exe v1.0.0 by Harrison Hsieh \n");
printf("===========================================\n");
printf("/C Init MyBIOS.ROM \n");
printf("/B [EC] [BIOS] Add Rom \n");
printf("Output : MyBios.ROM \n");
}
void InitBiosROM(char *argv[])
{
FILE *fo;
long i;
if ((fo = fopen (BiosRom, "wb")) == (FILE *) NULL)
{
exit(1);
}
for(i=0 ; i<= BIOSSIZE ; i++) //1MB
{
fputc(0x00,fo);
}
/* All done, close the file */
fclose (fo);
}
在說明完Build.c內的做法後,接著說明MyBIOS.bin 內的程式碼撰寫;
其實在MyBios.asm 中,我只有做4 件事情:
1. 設定好FFFF_FFF0h的第一條指令
2.開啟BigReal Mode (因為我要設定ICH9的RCRB內的暫存器,所以要開啟)
3.設定ICH9內的暫存器,把所有Port 80h的訊號轉送到LPC介面(我的Post card走LPC界面,所以要設定)
4.輸出99h 到Port 80h(所以LPC介面上面的Post card就會顯示99h)
底下是我的MyBIOS.asm 內的程式碼片段:
COLDBOOT:
CLI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 1. Enable big real mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
JMPREG di,Make4GBSegmentDI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 2. Set RCRB base address
;; 3. Config ICH9 Register
;; 4. Out 99h to Port 80h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
....
mov dx, 0cfch
mov eax,RCRB_BaseAddr
out dx, eax
....
and BYTE PTR es:[esi], NOT (04h) ; RCRB+xxxxh bit 2=0 Output to LPC
....
fPostCode:
mov al,099h
mov dx,80h
out dx,al
jmp fPostCode ;無窮回圈ㄧ直顯示99h
...
...
wbinvd ; ...begins here on power up
PUBLIC POWER
POWER:
JMP COLDBOOT ; first jump
DB '11/14/07',00,00,00 ; My release marker
以上就是我撰寫的程式碼內容的說明,其實沒有用到什麼特別的東西,如果說比較難的部份大概就是如何把程式碼塞到正確的位址吧。
總結:
純手工打造你自己的x86 BIOS 文章(1)~(4) 在這邊就做一個結束,在這幾篇文章中的實驗我主要是要幫助剛入門的BIOS新手去了解整個BIOS vendor提供的BIOS環境架構以及實際上BIOS code撰寫的第一步,因為很多東西都是入門的第一步比較難。
還記得ㄧ年前我剛入行的時候,我們學長跟我說寫BIOS最簡單的方式就是自己把一個BIOS寫到能開機你大概就已經學會了,雖然我離能自己寫到開機還有一段距離,不過在學習的過程中也學到了很多東西,因此當初會想自己純手工寫一個能讓x86 CPU執行一段BIOS code的環境也是希望能幫助更多BIOS入門時遇到挫折的朋友 ^^Y。
BIOS Boot Specification
最近有些朋友問我有關BEV以及BCV的相關資訊,這邊轉貼一篇之前收集的文章中的部分內容,希望對大家有幫助。
原文章出處:http://tw.myblog.yahoo.com/jw!T20aSgeaCQdebnoX0CAb9Xk-/article?mid=17
~以下是轉貼內容~
BIOS Boot Specification
完整的文件可以參考
http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
以下為一些重點整理
BBS (BIOS Boot Specification) 是用來規範 BIOS 如何選擇啟動裝置。它包含了
1. 辨識系統中的 IPL (Initial Program Load) 裝置
2. 根據使用者的選擇,尋訪每個裝置並檢視它是否能夠啟動系統
IPL
IPL 指的是可以啟動載入並執行作業系統的裝置。他包含了像是 Floppy, Hard drives, CD-ROM, PCMCIA conrtollers/cards, PnP Cards, Legacy cards 甚至像是 Network, Serial port, Parallel port 等等可開機的實體或虛擬裝置。
所有的 IPL 可以被歸類成下列三種
1. BAID
2. PnP Card (可再細分為 BCV 和 BEV 兩種裝置)
3. Legacy IPL Device
BAID (BIOS Aware IPL Device):
此類 IPL 需要 BIOS 的程式碼支援,來提供它啟動系統的能力。通常啟動的程式碼內建於 INT 19h (BIOS Bootstrap loader) 的服務之中。常見的裝置如下:
First floppy drive, First ATA Hard drive, PCI ATA card drive, ATAPI CD-ROM drive, PCMCIA controller bootable card, Ethernet controller code embedded in BIOS
PnP Cards:
此類 IPL 裝置,必須附加 option ROM 於 C0000h-EFFFFh (2K boundary)。而且在 Option ROM 中必須有 PnP Option ROM Header (Table 2)。另外,開機相關資訊會被記錄在 PnP Expansion Header (Table 3),在此表格中,包含了 BCV 或 BEV 的指標。
BCV (Boot Connection Vector):
BCV 是一個指標,指向 Option ROM 中的某一段程式碼。這段程式碼負責執行裝置的初始化、偵測硬體 (例如是否有 SCSI 裝置連接到系統) 或者在必要時 Hook INT 13h 的服務 (Disk I/O)。常見的有:
PnP SCSI card drive, NoN-PnP card PnP Expansion Header
BEV (Bootstrap Entry Vector):
BEV 是一個指標,指向 Option ROM 中負責載入作業系統的一段程式碼,並在必要時 Hook INT 18h 或 INT 19h 的服務。通常於網路卡裝置的 Network Remote Boot 時使用。常見的有:
PnP Token Ring card, PnP Ethernet card, NoN-PnP card PnP Expansion Header
Legacy IPL Devices:
此類裝置為標準的 ISA Card,其包含了一個 Option ROM 於 C0000h-EFFFFh (2K boundary)。此類型的裝置於 Option ROM 並沒有 PnP Expansion Header 的相關資訊。在它的 Option ROM 被 BIOS 找到時,會先執行一段初始化的程式。這段程式執行期間,會根據需要來 Hook INT 19h, INT 18h 以及 INT 13h。
IPL Table
每個 BAID 以及 BEV 裝置必須在 IPL Table 中有一個相對應的欄位
範例
0: Floppy A:
1: Hard Drive C:
2: CD-ROM
3: BEV #1
4: BEV #2
IPL Priority
IPL Priority 決定 IPL 開機的順序。它存在於非揮發性記憶體中,並且可以讓使用者修改。在 INT 19h (載入作業系統) 呼叫中,它必須能夠被取用,並且根據表格中的順序來進行開機的程序。
BCV Priority
在 BIOS INT 13h (Disk I/O) 的服務之中,磁碟機代號 00-7Fh 為 Floppy Disk, 而 80-FFh 為 Fixed Disk。而這些代號和實體磁碟的對應必須在 BIOS 中完成。另外值得注意的一點就是,由於只有第一台 Floppy 和第一台 Fixed Disk 可以用來啟動 (代號 00h 以及 80h),所以根據不同的啟動設定,也必須將 INT 13h Hook 的順序作調整才能夠順利開機。
舉例來說,如果 ATA 硬碟占用掉 80h,而 SCSI 只能占用 81h 之後的磁碟機代號的話,那麼 SCSI 硬碟就不能作為開機的硬碟了。
範例
BCV Table
0: ATA Drives
1: Legacy Cards
2: BCV #1
3: BCV #2
BCV Priority
0: 2 (BCV #1)
1: 0 (ATA Drives)
2: 1 (Legacy Cards)
3: 3 (BCV #2)
INT 13h 支援的裝置有下列幾種
1. ATA Drive
2. PnP Cards with BCVs
3. Legacy Cards with Option ROMs
4. Hard Drive BAID
關於 INT 13h 的幾個重點
1. 當 INT 13h 被 Hook 時,舊的 INT 13h Vector 必須被保存
2. 已經安裝的硬碟數目必須被保存在 BDA 0040:0075
3. 第一個安裝的硬碟會得到 80h 的代號,這也代表著它是開機硬碟
4. 一旦安裝到 INT 13h 之後,就不能被解除安裝
INT 19h
在這個服務呼叫時,所有的 IPL 已經被辨識,並且 INT 13h 的裝置也都已安裝完成。在呼叫之後,它會根據 IPL Priority 中的裝置,呼叫其 Boot handler。第一個呼叫成功的裝置會負責載入作業系統。如果全部的裝置都已呼叫過後還沒有成功載入作業系統,它會顯示一個錯誤訊息,並且等待重新開始。
INT 18h
原本的 INT 18h 的動作是將控制權交給 BIOS,顯示一個錯誤訊息並且等待使用者按下按鍵後進行下一個動作。而在 BBS 中重新定義 INT 18h 的功能為錯誤回復的中斷向量。這裡要注意的是 INT 18h 並不會返回至呼叫它的程序,並且在一開始就將堆疊重新設定。
Boot Menu (Optional)
在 POST 期間,部份 BIOS 充許使用者使用一個特定的 Hot Key 來呼叫 Boot Menu,並用它來改變 INT 19h 所使用的啟動裝置。這裡要注意的是,這個動作並不會改變 IPL Priority 的內容,它只是單純地選擇啟動的裝置。
一些相關的表格
Table 1 - IPL Table and BCV Table Entry Data Structure
Name Offset Size Description
deviceType 00h WORD See definitions below
statusFlags 02h WORD See bit definitions below
bootHandler 04h FAR PTR Far pointer to address of boot handler
descString 08h FAR PTR Far pointer to ASCIIZ description string
expansion 0Ch DWORD Reserved for future expansion
deviceType:
00h = Reserved
01h = Floppy
02h = Hard disk
03h = CD-ROM
04h = PCMCIA
05h = USB device
06h = Embedded network
07h..7Fh = Reserved
80h = BEV device
81h..FEh = Reserved
FFh = Unknown
Table 2 - PnP Option ROM Header
Offset Size Value Description
00h BYTE 55h Signature byte 1
01h BYTE AAh Signature byte 2
02h BYTE Varies Option ROM length in 512-byte blocks
03h DWORD Varies Initialization entry point
07h 17BYTES Varies Reserved.
18h WORD Varies Offset to PCI data structure
1Ah WORD Varies Offset to expansion header structure
Table 3 - PnP Expansion Header
0ffset Size Value Description
00h BYTE '$' Signature byte 1
01h BYTE 'P' Signature byte 2
02h BYTE 'n' Signature byte 3
03h BYTE 'P' Signature byte 4
04h BYTE 01h Structure revision
05h BYTE Varies Length (in 16 byte increments)
06h WORD Varies Offset of next header (0000h if none).
08h BYTE 00h Reserved
09h BYTE Varies Checksum
0Ah DWORD Varies Device identifier
0Eh WORD Varies Pointer to manufacturer string (Optional)
10h WORD Varies Pointer to product name string (Optional)
12h 3BYTES Varies Device type code
15h BYTE Varies Device indicators
16h WORD Varies Boot Connection Vector (BCV), 0000h if none
18h WORD Varies Disconnect Vector (DV), 0000h if none
1Ah WORD Varies Bootstrap Entry Vector (BEV), 0000h if none
1Ch WORD 0000h Reserved
1Eh WORD Varies Static resource information vector, 0000h if none
Table 4 - PCI Data Structure
00h BYTE 'P' Signature byte 1
01h BYTE 'C' Signature byte 2
02h BYTE 'I' Signature byte 3
03h BYTE 'R' Signature byte 4
04h WORD Varies Vendor Identification
06h WORD Varies Device Identification
08h WORD Varies Pointer to Vital Product Data
0Ah WORD Varies PCI Data Structure Length
0Ch BYTE Varies PCI Data Structure Revision
0Dh 3BYTES Varies Class Code
10h WORD Varies Image Length
12h WORD Varies Revision Level of Code/Data
14h BYTE Varies Code type
15h BYTE Varies Indicator
16h WORD Reserved
原文章出處:http://tw.myblog.yahoo.com/jw!T20aSgeaCQdebnoX0CAb9Xk-/article?mid=17
~以下是轉貼內容~
BIOS Boot Specification
完整的文件可以參考
http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
以下為一些重點整理
BBS (BIOS Boot Specification) 是用來規範 BIOS 如何選擇啟動裝置。它包含了
1. 辨識系統中的 IPL (Initial Program Load) 裝置
2. 根據使用者的選擇,尋訪每個裝置並檢視它是否能夠啟動系統
IPL
IPL 指的是可以啟動載入並執行作業系統的裝置。他包含了像是 Floppy, Hard drives, CD-ROM, PCMCIA conrtollers/cards, PnP Cards, Legacy cards 甚至像是 Network, Serial port, Parallel port 等等可開機的實體或虛擬裝置。
所有的 IPL 可以被歸類成下列三種
1. BAID
2. PnP Card (可再細分為 BCV 和 BEV 兩種裝置)
3. Legacy IPL Device
BAID (BIOS Aware IPL Device):
此類 IPL 需要 BIOS 的程式碼支援,來提供它啟動系統的能力。通常啟動的程式碼內建於 INT 19h (BIOS Bootstrap loader) 的服務之中。常見的裝置如下:
First floppy drive, First ATA Hard drive, PCI ATA card drive, ATAPI CD-ROM drive, PCMCIA controller bootable card, Ethernet controller code embedded in BIOS
PnP Cards:
此類 IPL 裝置,必須附加 option ROM 於 C0000h-EFFFFh (2K boundary)。而且在 Option ROM 中必須有 PnP Option ROM Header (Table 2)。另外,開機相關資訊會被記錄在 PnP Expansion Header (Table 3),在此表格中,包含了 BCV 或 BEV 的指標。
BCV (Boot Connection Vector):
BCV 是一個指標,指向 Option ROM 中的某一段程式碼。這段程式碼負責執行裝置的初始化、偵測硬體 (例如是否有 SCSI 裝置連接到系統) 或者在必要時 Hook INT 13h 的服務 (Disk I/O)。常見的有:
PnP SCSI card drive, NoN-PnP card PnP Expansion Header
BEV (Bootstrap Entry Vector):
BEV 是一個指標,指向 Option ROM 中負責載入作業系統的一段程式碼,並在必要時 Hook INT 18h 或 INT 19h 的服務。通常於網路卡裝置的 Network Remote Boot 時使用。常見的有:
PnP Token Ring card, PnP Ethernet card, NoN-PnP card PnP Expansion Header
Legacy IPL Devices:
此類裝置為標準的 ISA Card,其包含了一個 Option ROM 於 C0000h-EFFFFh (2K boundary)。此類型的裝置於 Option ROM 並沒有 PnP Expansion Header 的相關資訊。在它的 Option ROM 被 BIOS 找到時,會先執行一段初始化的程式。這段程式執行期間,會根據需要來 Hook INT 19h, INT 18h 以及 INT 13h。
IPL Table
每個 BAID 以及 BEV 裝置必須在 IPL Table 中有一個相對應的欄位
範例
0: Floppy A:
1: Hard Drive C:
2: CD-ROM
3: BEV #1
4: BEV #2
IPL Priority
IPL Priority 決定 IPL 開機的順序。它存在於非揮發性記憶體中,並且可以讓使用者修改。在 INT 19h (載入作業系統) 呼叫中,它必須能夠被取用,並且根據表格中的順序來進行開機的程序。
BCV Priority
在 BIOS INT 13h (Disk I/O) 的服務之中,磁碟機代號 00-7Fh 為 Floppy Disk, 而 80-FFh 為 Fixed Disk。而這些代號和實體磁碟的對應必須在 BIOS 中完成。另外值得注意的一點就是,由於只有第一台 Floppy 和第一台 Fixed Disk 可以用來啟動 (代號 00h 以及 80h),所以根據不同的啟動設定,也必須將 INT 13h Hook 的順序作調整才能夠順利開機。
舉例來說,如果 ATA 硬碟占用掉 80h,而 SCSI 只能占用 81h 之後的磁碟機代號的話,那麼 SCSI 硬碟就不能作為開機的硬碟了。
範例
BCV Table
0: ATA Drives
1: Legacy Cards
2: BCV #1
3: BCV #2
BCV Priority
0: 2 (BCV #1)
1: 0 (ATA Drives)
2: 1 (Legacy Cards)
3: 3 (BCV #2)
INT 13h 支援的裝置有下列幾種
1. ATA Drive
2. PnP Cards with BCVs
3. Legacy Cards with Option ROMs
4. Hard Drive BAID
關於 INT 13h 的幾個重點
1. 當 INT 13h 被 Hook 時,舊的 INT 13h Vector 必須被保存
2. 已經安裝的硬碟數目必須被保存在 BDA 0040:0075
3. 第一個安裝的硬碟會得到 80h 的代號,這也代表著它是開機硬碟
4. 一旦安裝到 INT 13h 之後,就不能被解除安裝
INT 19h
在這個服務呼叫時,所有的 IPL 已經被辨識,並且 INT 13h 的裝置也都已安裝完成。在呼叫之後,它會根據 IPL Priority 中的裝置,呼叫其 Boot handler。第一個呼叫成功的裝置會負責載入作業系統。如果全部的裝置都已呼叫過後還沒有成功載入作業系統,它會顯示一個錯誤訊息,並且等待重新開始。
INT 18h
原本的 INT 18h 的動作是將控制權交給 BIOS,顯示一個錯誤訊息並且等待使用者按下按鍵後進行下一個動作。而在 BBS 中重新定義 INT 18h 的功能為錯誤回復的中斷向量。這裡要注意的是 INT 18h 並不會返回至呼叫它的程序,並且在一開始就將堆疊重新設定。
Boot Menu (Optional)
在 POST 期間,部份 BIOS 充許使用者使用一個特定的 Hot Key 來呼叫 Boot Menu,並用它來改變 INT 19h 所使用的啟動裝置。這裡要注意的是,這個動作並不會改變 IPL Priority 的內容,它只是單純地選擇啟動的裝置。
一些相關的表格
Table 1 - IPL Table and BCV Table Entry Data Structure
Name Offset Size Description
deviceType 00h WORD See definitions below
statusFlags 02h WORD See bit definitions below
bootHandler 04h FAR PTR Far pointer to address of boot handler
descString 08h FAR PTR Far pointer to ASCIIZ description string
expansion 0Ch DWORD Reserved for future expansion
deviceType:
00h = Reserved
01h = Floppy
02h = Hard disk
03h = CD-ROM
04h = PCMCIA
05h = USB device
06h = Embedded network
07h..7Fh = Reserved
80h = BEV device
81h..FEh = Reserved
FFh = Unknown
Table 2 - PnP Option ROM Header
Offset Size Value Description
00h BYTE 55h Signature byte 1
01h BYTE AAh Signature byte 2
02h BYTE Varies Option ROM length in 512-byte blocks
03h DWORD Varies Initialization entry point
07h 17BYTES Varies Reserved.
18h WORD Varies Offset to PCI data structure
1Ah WORD Varies Offset to expansion header structure
Table 3 - PnP Expansion Header
0ffset Size Value Description
00h BYTE '$' Signature byte 1
01h BYTE 'P' Signature byte 2
02h BYTE 'n' Signature byte 3
03h BYTE 'P' Signature byte 4
04h BYTE 01h Structure revision
05h BYTE Varies Length (in 16 byte increments)
06h WORD Varies Offset of next header (0000h if none).
08h BYTE 00h Reserved
09h BYTE Varies Checksum
0Ah DWORD Varies Device identifier
0Eh WORD Varies Pointer to manufacturer string (Optional)
10h WORD Varies Pointer to product name string (Optional)
12h 3BYTES Varies Device type code
15h BYTE Varies Device indicators
16h WORD Varies Boot Connection Vector (BCV), 0000h if none
18h WORD Varies Disconnect Vector (DV), 0000h if none
1Ah WORD Varies Bootstrap Entry Vector (BEV), 0000h if none
1Ch WORD 0000h Reserved
1Eh WORD Varies Static resource information vector, 0000h if none
Table 4 - PCI Data Structure
00h BYTE 'P' Signature byte 1
01h BYTE 'C' Signature byte 2
02h BYTE 'I' Signature byte 3
03h BYTE 'R' Signature byte 4
04h WORD Varies Vendor Identification
06h WORD Varies Device Identification
08h WORD Varies Pointer to Vital Product Data
0Ah WORD Varies PCI Data Structure Length
0Ch BYTE Varies PCI Data Structure Revision
0Dh 3BYTES Varies Class Code
10h WORD Varies Image Length
12h WORD Varies Revision Level of Code/Data
14h BYTE Varies Code type
15h BYTE Varies Indicator
16h WORD Reserved
標籤:
IA32 相關基礎知識
Flat Memory Mode
最近在逛ㄧ些網站看到下面這篇文章,在講所謂的Flat Memory Mode,由於資料說明的很詳細,所以就收集文章在自己部落格中,有興趣的朋友可以去原作者部落格看這篇的完整文章,以下是轉貼部份內容。
原文章出處:http://w3tony.blogspot.com/2006/04/flat-real-mode_114619442075796383.html
~以下是轉貼內容~
Flat real mode 或者是 unreal Mode,名詞很多,不過主要的用處都一樣,在 Real Mode 存取超過 1MB 以上的記憶體空間,下面就來介紹怎麼進入 Flat Real Mode。
要能夠使用 32bit 的 segment,首先需要進入保護模式,最簡單的方法是:
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
cli 的目的是將中斷遮蔽,避免臨時的中斷服務打斷我們的工作,透過設定 CR0 的 PE bit 就可以進入 Protected Mode,接下來我們需要 descriptor table 才能夠將 segment limit 從 64K 換成 4G,
DataSel = 8
GDT dw 4 dup(0) ; NULL descriptor
dw 0ffffh,0ffh,9200h,8fh ;Data segment descriptor
GDT_ptr label fword
dw offset GDTptr-1-offset GDT
dd offset GDT
DataSel 指 Data segment entry 的 selector,設定為 8 表示我們的 entry 是在 NULL Descriptor 的下一個位置,GDT_ptr 用來存放 GDT Table 的長度以及 GDT Table 的 Linear Address,再來我們要將 GDT Table 載入到 gdt 暫存器,方法如下
mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
然後需要一個 jump 的動作,目的是清除 instruction queue 的 real mode instruction:
mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
jmp short pmode ; Clear the execution pipe
pmode:
mov ax,DataSel ; 進入保護模式
mov ds,ax ; 設定 selector limits 為 4 GB
mov es,ax
mov fs,ax
mov gs,ax
現在我們已經進入 Protected Mode,不過這樣只是單純的保護模式,還不是 Flat Real Mode,所以我們還需要一個步驟,返回 Real Mode,方法如下:
mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
jmp short pmode ; Clear the execution pipe
pmode:
mov ax,DataSel ; 進入保護模式
mov ds,ax ; 設定 selector limits 為 4 GB
mov es,ax
mov fs,ax
mov gs,ax
jmp short Real_mode
Real_mode:
clc;我們已經返回 real mode了並且將 carry flag 清除,通常這代表正確執行
sti ;解除中斷遮蔽
ret
進行到這,我們已經將 fs 與 gs 設定成 4G 範圍的 segment,試試看使用
mov eax, 6400000H
mov edi, eax
mov eax, dword ptr gs:[edi]
能不能讀取到 100MB 的記憶體內容,是不是很有趣?Flat real mode 的應用很多,不過有個很大的缺點,執行的 code 還是只能放在 1MB 的範圍,只有 data 才能存取 4GB 的空間。往後我還會繼續介紹怎麼返回真實模式,有許多注意事項是常常被人乎略的,尤其是當我們需要重複進入跟退出保護模式時,很容易破壞暫存器的設定,例如 SS:SP 就是最常忘記的地方,下次有機會再繼續討論這個部份。
延伸閱讀:
Flat real mode
http://www.df.lth.se/~john_e/gems/gem0022.html
Flat real mode interface http://www.programmersheaven.com/zone5/cat19/1365.htm
原文章出處:http://w3tony.blogspot.com/2006/04/flat-real-mode_114619442075796383.html
~以下是轉貼內容~
Flat real mode 或者是 unreal Mode,名詞很多,不過主要的用處都一樣,在 Real Mode 存取超過 1MB 以上的記憶體空間,下面就來介紹怎麼進入 Flat Real Mode。
要能夠使用 32bit 的 segment,首先需要進入保護模式,最簡單的方法是:
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
cli 的目的是將中斷遮蔽,避免臨時的中斷服務打斷我們的工作,透過設定 CR0 的 PE bit 就可以進入 Protected Mode,接下來我們需要 descriptor table 才能夠將 segment limit 從 64K 換成 4G,
DataSel = 8
GDT dw 4 dup(0) ; NULL descriptor
dw 0ffffh,0ffh,9200h,8fh ;Data segment descriptor
GDT_ptr label fword
dw offset GDTptr-1-offset GDT
dd offset GDT
DataSel 指 Data segment entry 的 selector,設定為 8 表示我們的 entry 是在 NULL Descriptor 的下一個位置,GDT_ptr 用來存放 GDT Table 的長度以及 GDT Table 的 Linear Address,再來我們要將 GDT Table 載入到 gdt 暫存器,方法如下
mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
然後需要一個 jump 的動作,目的是清除 instruction queue 的 real mode instruction:
mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
jmp short pmode ; Clear the execution pipe
pmode:
mov ax,DataSel ; 進入保護模式
mov ds,ax ; 設定 selector limits 為 4 GB
mov es,ax
mov fs,ax
mov gs,ax
現在我們已經進入 Protected Mode,不過這樣只是單純的保護模式,還不是 Flat Real Mode,所以我們還需要一個步驟,返回 Real Mode,方法如下:
mov ax,cs
mov ds,ax
movzx eax,ax
shl eax,4
add dword ptr ds:GDT_ptr+2,eax ;將 GDT 的 Linear Address 存入 GDT_ptr
lgdt fword ptr ds:GDT_ptr ;載入 GDT table
cli
mov eax,cr0
or al,1
mov cr0,eax
sti
jmp short pmode ; Clear the execution pipe
pmode:
mov ax,DataSel ; 進入保護模式
mov ds,ax ; 設定 selector limits 為 4 GB
mov es,ax
mov fs,ax
mov gs,ax
jmp short Real_mode
Real_mode:
clc;我們已經返回 real mode了並且將 carry flag 清除,通常這代表正確執行
sti ;解除中斷遮蔽
ret
進行到這,我們已經將 fs 與 gs 設定成 4G 範圍的 segment,試試看使用
mov eax, 6400000H
mov edi, eax
mov eax, dword ptr gs:[edi]
能不能讀取到 100MB 的記憶體內容,是不是很有趣?Flat real mode 的應用很多,不過有個很大的缺點,執行的 code 還是只能放在 1MB 的範圍,只有 data 才能存取 4GB 的空間。往後我還會繼續介紹怎麼返回真實模式,有許多注意事項是常常被人乎略的,尤其是當我們需要重複進入跟退出保護模式時,很容易破壞暫存器的設定,例如 SS:SP 就是最常忘記的地方,下次有機會再繼續討論這個部份。
延伸閱讀:
Flat real mode
http://www.df.lth.se/~john_e/gems/gem0022.html
Flat real mode interface http://www.programmersheaven.com/zone5/cat19/1365.htm
標籤:
IA32 相關基礎知識
訂閱:
文章 (Atom)