The following is a list of some grub4dos internal variables and functions from a 2013 or later version of a chenall build of grub4dos (as used in RMPrepUSB).
Memory areas used by grub4dos
The physical memory address range from 1M to 32M is reserved for grub4dos internal code and data. Grub4dos may fail to run on systems with less than 32MB of RAM. Ideally users should not use this range (32MB = 0x200,0000 = below (md)0x10000).
Some use of (md)0x300 is relatively safe if low memory is required.
Some areas below 1MB are also used by grub4dos.
Grub4dos executes grub4dos executables and kernel payloads at 32MB in memory, therefore it is best to use memory areas well above 32MB for any memory workspace if you intend to call grub4dos executables after loading kernel files, etc.
Note: In grub4dos, batch files and programs run in the same piece of memory as the 'kernel' command. Therefore you cannot use the kernel command directly from a batch file or grub4dos program.
To workaround this, either allocate memory to move the buffer by using call Fn.50 0x200000 as the very first line in menu.lst OR use configfile, e.g.
(md) is a memory 'device'. (md)x+y where x is the start sector in memory and y is the length of memory in sectors (e.g. (md)4+2 = start at 2KB in memory for a length of 1KB. Note that the BIOS uses low memory!
Grub4dos use of memory - (md) uses 512-byte 'sectors':
0x0007000 CMD line buffer
0x0008200 320K fixed variables + grldr program = (md)0x41 to (md)0x300
0x0050000 to the end of low memory is used by gfxmenu
0x0030000 64k sector buffer for current device = (md)0x180 to (md)0x1FF
0x0045000 environment variables = (md)0x228 to (md)0x288 approx.
0x0060000 end of grub4dos variables + wkspace = (md)0x300
0x007C000 used to load boot code, etc. = (md)0x3E0...
0x0090000 may be used by BIOS (avoid) = (md)0x480 to (md)0x4FF
0x00A0000 graphics memory (reserved) = (md)0x500 to (md)0x5FF
0x00C0000 BIOS area (reserved) = (md)0x600 to (md)0x7FF
0x0100000 may be used by BIOS (avoid) = (md)0x800 best to avoid up to (md)0x880
0x02B0000 2.6MB HMA_ADDR = (md)0x1580
0x03E0000 FSYS_BUF = (md)0x1F00 to (md)0x1F40
0x0800000 8M for mem array workspace = (md)0x4000 to (md)0x7FFF
0x0A00000 10M-14M for page map = (md)0x5000-0x6FFF
0x1000000 16M-19M used to store background bmp = (md)0x8000-0xD460 (end of buffer depends on size of bitmap, 1920x1440=0xD460, 800x600=0x8EA6, 1024x768=0x9800)
0x1800000 24MB Unifont area = (md)0xC000-0xFFFF
0x2000000 32MB Reserved memory area = (md)0x10000
0x2800000 40MB Linux temp memory area = (md)0x14000
Avoid below (md)0x300 and (md)0x4000 to (md)0x7FFF area. Preferably use (md)0x10000 and above (above 32MB).
If only using graphics mode 1024x768 as max, then can use (md)0x9800 to (md)0xBFFF ??
Use of around (md)0x8000 to 0x9800 can cause corruption of bitmap background when a menu is displayed in 1024x768 mode (even more used in higher res modes!).
However wenv/insmod seems to load files above 32MB - therefore use above 50MB = (md)0x19000 to be safe!
Many BIOSes use the last part of segment 9000:0 for a scratchpad. All IBM-compatible BIOSes use A000:0 - F000:FFFF.
Black areas are normally unused by grub4dos and IBM PC BIOS and hardware.
(md)0x200 - 0x220 this seems to be used by chenall, et al. and so is probably safe!
(md)0x300 - 0x4FF 384-600KB approx. (0x3E0 may be used for chainloading by grub4dos)
(md)0x1000 - 0x3FFF 2-8MB
(md)0xD800 - 0xFFFFF (can start from 0x9800 as long as not using higher Res than 1024x768)
(md)0x19000 + (50MB+)
As most systems will have over 50MB of memory, use memory after (md)0x19000 to be ultra safe!
Using grub4dos variables
Grub4dos variables recognises a maximum name length 8 characters and each variable holds a maximum size of 511 characters or 512 bytes. The variable name is case sensitive, e.g.
e.g. do not exceed 8 characters for variable names or it could cause unexpected problems (FRED12345 in this example is shortened by grub4dos to FRED1234) ...
Note: Variables and their values are stored in memory and may share the same workspace area as modules loaded using the 'insmod' command. You may get crashes if you define too many variables and have lots of large modules loaded into memory (use delmod to remove the modules from memory after use).
#clear all variables except fred
set * && set fred=%fred%
You can define leading spaces in a variable and have characters like && or ;; by enclosing the argument in double-quotes (must start as "<variable>= with no spaces
set "a= fred && doris"
Be careful using && or || as the environment is not changed until the whole line has been executed - e.g. the following line will not print HELLO the first time it is run because A is not set until after the whole line has been executed:
set A=HELLO && echo %A%
Get the number of characters in any variable - this example prints 5
# set command will return the length set a=freda # do stuff here... # get length of a into @retval set a=%a% echo Number of characters in variable a = [email protected]%
To display all variables beginning with AB use:
You can use IF EXIST to test for the existence of a variable
if exist FRED echo Variable FRED exists!
Increasing the variable space
Grub4dos has space for 60 variables, each one can have a value size of 512 bytes.
# check if a variable has been defined
if exist FRED1234 echo FRED1234 is set to %FRED1234% || echo Variable FRED1234 has not been defined!
In the latest versions of grub4dos (15 May 2013 and later) you can extend the variable space using an undocumented @extend command:
You can set up to max 65,536 variables using @extend.
set @extend BASE_ADDR SIZE
The BASE_ADDR is the memory start of extended variable.
SIZE is how many variables it will extended by (MAX is 0xFFFF)
e.g. add 10 variables (so we can have 70 variables in total) at 0x40000.
set @extend 0x40000 10
this needs memory (((10+63)/64) + 10)*512 = 5632.
You must confirm the BASE_ADDR has enough space.
setlocal/endlocal will not work correctly however as any variables over the 60 that are set inside a setlocal section will remain after an endlocal!
So if you are using @extend and setlocal/endlocal, be sure to not use more than 60 variables inside the setlocal/endlocal segments!
set @extend 0x40000 10
set 70 variables here...
>>> 10 variables will be listed!
The first number is the base address in memory where the extra variable names are stored. The second number is the next unused block. The last number is the number of extra variables (above 60) that can be stored (10 variables = 200h*10 = 200 sectors from 0x40000 to 0x401FF).
You can get a substring of any variable like this: %variablename:~startpos,endpos%
The startpos shows where the substring begins ( + position from the beginning, - position from the end)
The endpos shows where it ends ( + position from the beginning, - position from the end)
A header file which may help if you understand C code can be found here.
Example - test string length of KEY is exactly 29 characters
if not "%KEY:~29,1%"=="" set KL=1 && echo TOO LONG!
if "%KEY%"=="%KEY:~0,28%" set KL=2 && echo TOO SHORT!
if not "%KL%"=="0" pause --wait=3 INVALID PRODUCT KEY "%KEY%"! && configfile /menu.lst
Filename strings in batch files (limitations)
Max no lines = 2048 in a batch file, Max. no. labels in a batch file = 128, file must start with !BAT on first line.
In a batch file, %0 is the full path of the batch file itself (if the batch file is in the root then no leading / is output), %~nx0 is the batch files filename + extension, %~n0 is just the filename and %~x0 is just the extension (e.g. .gb4).
n is filename, x is extension, p is the path and d is the drive name.
%0=/xx/fred.g4b (if in root then fred.g4b)
%~pnx0=/xx/fred.g4b (if in root then /fred.g4b)
%~0=parameter without quotes
%~f0=fully path of filename - e.g. if %0=fred.inf then %~f0=(hd1,0)/dir1/dir2/fred.inf if root was set to (hd1,0)/dir1/dir2
If you pass more than one filename to a batch file, %1 will be the second parameter, %2 the third, etc. %* is all parameters.
Batch file to get all parameters as arg1...argn and argc as number of parameters:
if "%1"=="" goto :fin
set /a argc=%argc%+1 > nul
Note: BEWARE! in batch files beware of %0 %1 %2 accidents! e.g.
will not display 32 (it displays %f because %1, %2 %3 special variables are substituted first, so grub4dos translates this to %f+%2) - instead use this...
%% in a batch file is reduced to %. Since %%2 does not mean anything to grub4dos on the first substitution pass, we get the expected answer.
If you have a filename or full or partial filespec, you can get bits of it like this:
@date - e.g. 2012-04-08
@time - e.g. 15:29:11
@random - 0 to 32767 - e.g. set/a num1to10=%@random%/3277+1 or set /a [email protected]:~-1,1% + 1
@root - e.g. (hd0,0)
@path - e.g. (bd)/BOOT/GRUB/
@retval - e.g. 1 - NOTE: This is a 32bit value ranging from -2GB to +2GB
?_BOOT - disk&partition that contained the file \grldr that was used to boot to grub4dos, e.g. (hd0,0) - note: this is NOT the same as (bd) which is set to whatever partition contained the menu.lst file.
?_UUID - set after uuid command - e.g. uuid (bd)
? - result of last command - e.g. cat --locate=string --number=1 /myfile ;& set offset=%?% ;& echo string found at %offset% prints 0x1de or 0x0 if not found, @retval is 0 if not found or <count> if found
You can set the default file extensions of grub4dos executables using command --set-ext= (this is similar to typing just fred in the Windows command shell and Windows would run fred.exe) - for example, we can set the default extensions like this:
If you then have a command like fred or /fred in a menu or batch file, grub4dos will try “fred" first and then fred.g4b and then fred.g4x.
Tip: use debug msg=3 to see the search paths used by grub4dos.
You can call an internal function like sprintf within a grub4dos menu or a grub4dos batch file. For example:
call Fn.0 0 "stringa=%s stringb=%s" %a% %b%
this prints on the display
Here is a list of the Fn calls. I don't know all the details for all the parameters, but each parameter should be separated by a space.
Note that Fn. is case sensitive and must have a capital F and a lowercase n.
Some equivalent C library functions for these can be searched for here.
0 grub_sprintf syntax: call Fn.0 <memory location> <printf string> - if <memory location> = 0 then is output to screen, if <memory location>=0x60000 then the string is output to memory at (md)0x300. @retval returns the length of the string - e.g. call Fn.0 0x60000 "%pci%\r\n" = call func sprintf("%pci%") - another example: call Fn.0 0 "id="%s","%1"" %p_hwid% - This function is also useful for stripping quote marks from variables (but ensure there is only one pair or things can go wrong! Also note that Fn.0 0 fred will output 'fred' but Fn.0 0 1234 will not work as it is treated as a number - use Fn.0 0 "1234" instead.) call Fn.0 0 0xFFFF5 | set biosdate= will return the date of the BIOS on most systems - e.g. 06/23/99
2 putchar - e.g. call Fn.2 49 prints '1' (if in the text mode console, call Fn.2 7 will 'beep' the internal speaker if your BIOS and hardware supports it - i.e. if it is a PC and has a 'beeper-speaker' fitted!)
3 get_cmdline_obsolete 4 getxy The return value is ((X << 8) | Y). 5 gotoxy - e.g. call Fn.5 0 11 set cursor pos to beginning of line 11 6 cls
7 wee_skip_to was obsolete setcursor 8 nul_terminate 9 safe_parse_maxint_with_suffix 10 substring 11 grub_strstr - see here - find string in string, returns @retval as position of string start, e.g. call Fn.11 0x6000 "$" || exit or call Fn.11 "%filefind%" "0" && echo found 0 in %filefind% 12 grub_strlen - e.g. call Fn.12 "freddy" ;; echo [email protected]% - prints 6 13 grub_strtok - seeherefor definition e.g. echo 123,456,789 > (md)0x200+1 ;; call Fn.13 0x40000 "," ;; echo First string at [email protected]% ;; call Fn.13 0 "," ;; echo Next string at [email protected]% ;; cat --skip=262152 (md)0+0x201 (note: memory is changed by each call a 0 is inserted at the delimiting character position -> 123<0>456<0>789
14 grub_strncat - Appends the first num characters of source to destination, plus a terminating null-character 15 grub_strcmp compare two strings - e.g. call Fn.15 XXX XXX ;; echo [email protected]% returns 0 (or -1 if no match) 16 grub_strcpy - copies string into destination
18 reserved 19 getkey - gets a kbd key from BIOS kbd buffer 20 checkkey- get kbd key without emptying buffer - e.g. call Fn.20 ;; set /A [email protected]%&0xff > nul ;; echo %key% prints 0x31 if number 1 key pressed (top 8 bits is scancode, bottom 8 are ASCII code, Function keys are 'special') @retval returns -1 if no key available. 21 22 grub_memcmp
24 grub_memset (32-bit) call Fn.24 0x83562 0xaa 0x100 - fill address 0x83562 in memory with byte 0xaa for size of 256 bytes. Note: address must be 32-bit value max 2GB if signed number (not 64-bit value)
25grub_memset64 (64-bit) call Fn.25 0x83562 2 0xaa 0x12345678 0xA - fill 64-bit address 0x200083562 in memory (LSW MSW) with byte 0xaa for 64-bit size of 0xA12345678 bytes. Note: 64-bit values as unsigned 32-bit+32-bit (LSW MSW) New 2017-02 and later grldr only 26 grub_open - e.g. directly call grub_open file function it will put filesize at memory 0x8320 - this works well for non-compressed files too. call Fn.26 /myfile.gz ;; set /a filesize=*0x8320 27 grub_read
41 parse_string 42 hexdump - e.g. call Fn.42 0x8000 0 3 - list 3 hex bytes at 0x8000
53 realmode_run - executes a BIOS interrupt in real mode - e.g. see date.g4b batch file for example.
54 reserved for wee
55 reserved for wee
56 reserved for wee
57 reserved for wee
58 reserved for wee
59 reserved for wee
60 reserved for wee 61 dir - e.g. Fn.61 /dir/
67 unicode_to_utf8 e.g. call Fn.67 *0x82d0 0x60000 3 cat (md)0x300+1,1 | set nt_ver=NT
69 rawwrite 70 setcursor x (returns previous cursor state as [email protected]%) e.g. call Fn.70 0 to disable cursor and splashimage, call Fn.70 3 && clear will keep the splashscreen visible in console mode (but scrolling doesn't work when the cursor gets to the bottom of the screen so must clear the screen when get to bottom!) - 1=show cursor and disable splashimage, 2=normal splashimage mode,
72 grub_isspace 73 grub_sleep e.g. call Fn.73 3 to sleep for 3 secs
77 rectangle (x y w h border_width) - e.g. call Fn.77 180 180 100 100 2 - values in pixels not lines. Can be called multiple times for multiple rectangles on screen.
Internal variable memory locations used by grub4dos
When grub4dos loads into memory, it will store certain internal, local values at defined places within memory. Sometimes it is useful to read or write to these locations.
For instance, the grub4dos version number is held at location 0x8278 in memory. So you can check what version the user is running by adding these lines to your grub4dos menu.lst file:
checkrange 20120201:-1 read 0x8278 || pause --wait=3 Please use grub4dos-0.4.5c-2012-02-01 or later! && exit 1
This checks the value of 0x8278 to ensure it is between 20120201 (the date that the grub4dos version was made) and -1 (which is the largest possiblenumber). If this check fails then the message is displayed with a 3 second countdown and then the menu is exited.
Some variable locations + examples are given in the lists below: Use latest version available or these may not work (they may be subject to change)!
0000:82051 (BYTE) Control bits - default=0 (bit0=disable PXE, 1=disable kbd during boot, 2=disable unconditional cmd line entrance, 3=disable geometry tune, 4=dis cd-rom startup lookup, 5=enable HLT in checkkey idle loop for less CPU activity/heat)
0000:82084 (DWORD)install_partition (the boot partition) (??)
0000:8274 2 (WORD) default menu entry
0000:8276 1 (BYTE) current selected menu entry set /a SELMENU=*0x8276 & 0xff
0000:8278 4 (DWORD) grub4dos version - e.g. 20161109 = 0x133A255
0000:82804 (DWORD)boot_drive (the boot drive) set /A BD=*0x8280&0xf0 if %BD%==0x80 echo We booted from a hard disk!
0000:82844 (DWORD)pxe_yip (your ip)
0000:82884 (DWORD)pxe_sip (server ip)
0000:828C4 (DWORD)pxe_gip (gateway ip)
0000:82908 (QWORD)filesize (file size by last "cat --length=0")
0000:82984 (DWORD)saved_mem_upper (extended memory size in KB)
0000:829C4 (DWORD)saved_partition (current root partition) Only 2nd WORD is valid - use set /A PART=*0x829e&0xff (orset /a cur_pri=*0x829C>>16&0xFFFF)
0000:82A04 (DWORD)saved_drive (current root drive) set /a cur_drv=*0x82A0&0x7F