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).
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..
Grub4dos use of memory:
0x008200 @ 320K fixed variables + program = (md)0x41 to (md)0x300
0x030000 64k sector buffer for current device = (md)0x180 to (md)0x1FF0x045000 environment variables = (md)0x228
0x800000 8M for mem array workspace = (md)0x4000 to (md)0x7FFF
0xA00000 10M-14M for page map = (md)0x5000-0x6FFF (end used by background bitmap buffers - may extend to 0xA000+ if large bitmap?)
Avoid below (md)0x300 and (md)0x4000 to (md)0x7FFF area. Preferably use (md)0x10000 and above (above 32MB).
Use of around (md)0x9000 can cause corruption of bitmap background when a menu is displayed.
However wenv/insmod seems to load files above 32MB - therefore use above 50MB (md)0x19000 to be safe!
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).
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
Grub4dos has space for 60 variables, each one can have a value size of 512 bytes.
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.
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.
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!
>>> 10 variables will be listed!
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)
echo %a:~0,3% displays 012
echo %a:~2,3% displays 234
echo %a:~-3,3% displays xyz
echo %a:~3% displays 3456789abcdefghijklmnopqrstuvwxyz
echo %a:~3,-2% displays 3456789abcdefghijklmnopqrstuvwx
echo %a:~,-2% displays 0123456789abcdefghijklmnopqrstuvwx
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
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.
If you pass more than one filename to a batch file, %1 will be the second parameter, %2 the third, etc.
Batch file to get all parameters as arg1...argn and argc as number of parameters:
If we have a number of variables FRED1, FRED2, FRED3, etc, and we want to print out the value of each, we can use a counter like this
Note that using ^ anywhere inside a variable prevents it from being translated into a value. So %^FRED%N%%% gets translated by 'call' to %FRED1% and then echo displays the FRED1's value.
If not using a batch file use call echo %^FRED%N%% instead (in a batch file, %%=%).
grub4dos has a few predefined variables - these can be used in a grub4dos command - e.g. echo %@date% or set d=%@date%
These are case sensitive:
@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 num1to10=%@random:~-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 - original active boot partition, 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 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
1 grub_putstr2 putchar - e.g. call Fn.2 49 prints '1' (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!)
4 getxy The return value is ((X << 8) | Y).
5 gotoxy - e.g. call Fn.5 0 2 set cursor pos to beginning of line 11
7 wee_skip_to was obsolete setcursor
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 %@retval% - prints 6
13 grub_strtok - see here for definition e.g. echo 123,456,789 > (md)0x200+1 ;; call Fn.13 0x40000 "," ;; echo First string at %@retval% ;; call Fn.13 0 "," ;; echo Next string at %@retval% ;; 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 %@retval% returns 0 (or -1 if no match)
16 grub_strcpy - copies string into destination
19 getkey - gets a kbdchar
20 checkkey Check if any input character is available.
24 grub_memset call Fn.24 0x83562 0xaa 0x100 - fill address 0x83562 in memory with byte 0xaa for size of 256 bytes.
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
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
70 setcursor x (returns previous cursor state as %@retval%) 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,
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.
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:
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 possible number). 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:
Address Length Description
========= ======== ==============================================
0000:8208 4 (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:8280 4 (DWORD) boot_drive (the boot drive) set /A BD=*0x8280&0xf0 if %BD%==0x80 echo We booted from a hard disk!
0000:8284 4 (DWORD) pxe_yip (your ip)
0000:8288 4 (DWORD) pxe_sip (server ip)
0000:828C 4 (DWORD) pxe_gip (gateway ip)
0000:8290 8 (QWORD) filesize (file size by last "cat --length=0")
0000:8298 4 (DWORD) saved_mem_upper (extended memory size in KB)
0000:829C 4 (DWORD) saved_partition (current root partition)
0000:82A0 4 (DWORD) saved_drive (current root drive)
0000:82A4 4 (DWORD) no_decompression (no auto gunzip) 1=no decomp
0000:82A8 8 (QWORD) part_start (start sector of last partition)
0000:82B0 8 (QWORD) part_length (total sectors of last partition)
0000:82C0 8 (QWORD) saved_mem_higher (max contiguous mem in KB starting at 4G
0000:8308 1 (BYTE) character used for arrow symbol at left of highlighted menu entry (default=0x10 ►) - use 0 if not wanted or 0x1a for →
0000:8350 1 (BYTE) number of USB drive loaded by usb driver after usb --init command - e.g. 01 - read 0x8350 & 0xff
0000:8351 8 BYTES USB drive numbers loaded by internal g4d USB driver in order e.g. 0x808182
0000:8359 4 (DWORD) Base address of USB driver data area
0x8217 current configfile path and name e.g. call Fn.0 0 0x8217
0x826C BSS start address (4 bytes)
0x8274 autonumber boot entries with a hyphen after the number - write 0x8274 0x2d01
0x8276 set /a CURDEF=*0x8276 & 0ff gets current menu item number as a variable CURDEF
0x8278 check version of grub4dos - e.g. checkrange 20120201:-1 read 0x8278 || pause --wait=3 Please use grub4dos-0.4.5c-2012-02-01 or later! && exit 1
0x8290 Length of file in bytes -e.g cat --length=0 /myfile.iso ;; set /a LEN=*0x8290 ;; echo Length of file is %LEN% bytes (use if files could be over 4GB)
0x8298 maximum free memory in KB starting at 1M and below 4G (memory may NOT be contiguous) # calculate sizes in MB of iso and available memory - set /a MEMSIZE=*0x8298&0xFFFFFFFF>>10 ;; cat --length=0 /myfile.iso ;; set FSize=*0x8290>>20 ;; if %FSize%>=%MEMSIZE% echo Need More memory!
0x82BC CPU type - iftitle [checkrange 0,1 read 0x82Bc] 32bit system
0x8320 to get the expanded length of a compresses .gz file - use: cat --length=1 /myfile.gz ;& set /a filesize=*0x8320
# Or 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
0x8328 filepos ptr
New commands August 2014
write --bytes=1 0x8277 12 - writes a single byte to address 0x8277
crc32 ()/fred.iso - calculates crc32 of file
Note: these are undocumented and they could change at any time! Use them only if you have to:
VAR13 - filesystem type
VAR28 - graphics cursor
VAR29 - menu border character?
VAR42 - current color BG-FG as byte
VAR43 - low 32-bits foreground
VAR44 - low 32-bits background
VAR45 - cmd line string
VAR46 - splashimage loaded
ColoursGetting the current standard (console) text and background colours from internal system variables:
64-bit background colour - calc 44<<2 + *0x8304 ;; read %@retval% ;; set color_bg=%@retval%
64-bit text colour - calc 43<<2 + *0x8304 ;; read %@retval% ;; set color_fg=%@retval%
8-bit color if in textmode (first 4 bits are background, next 4 bits are text colour) - calc 42<<2 + *0x8304 ;; read %@retval% ;; set color_fb=%@retval%
See PrintMsg.zip for a batch file which prints a message in any colour but preserves the background colour. This works in both text mode and graphics mode and you don't need to know what the current text and background colours are.
# get the UUID of a volume containing the menu.lst file we used to run grub4dos (note: do NOT use && to join these lines!)
or you can use just one line:
Note that %^?% is used because %?% would be treated as a literal string and UUID would be set to %?% if ^? was not used!
^ anywhere inside a variable means do not translate to a variable - e.g. set a=%bb^bbb% returns a=%bbbbb%
Remove quotes from a string
call Fn.0 0 %id% | set id=
! can only be used after a && or || operator to mean 'else'
The && and || operators do not affect the environment until the whole line has been executed - e.g.
does not echo '1' because the environment is not updated until after the whole line has been executed. There are now three new operators:
;; - used to separate commands on the same line - e.g.
;& - as ;; but the next command is only executed if the result of the previous command was true, e.g.
;| - as ;; but next command is only executed if the previous command was false.
The syntax of write is:
write [--offset=SKIP] ADDR_OR_FILE INTEGER_OR_STRING
grub4dos will not allow writes to a compressed file. If grub4dos tries to read bytes from a compressed file it will try to decompress the file first.
If you are using an un-initialised memory area, you may find that the write to memory does not work on some systems or on some occasions.
may not write the string 'fred' to the memory area - this is usually because grub4dos thinks that the memory area being used holds a compressed file (which may just be random bytes of memory!). To overcome this you can either temporarily turn off compressed file (gzip and lzma) support using 0x82a4 or ensure the start of the memory area does not contain random bytes, as follows:
equally cat --hex (md)0x3000+1 may not work if grub4dos thinks that the file is a compressed file and if it cannot decompress it.
Press a letter (user presses d on keyboard)
d was pressed (0x64)!
(0x1 is returned by pause --wait=10 if no key is pressed within 10 seconds.)
cat --locate=fred (md)0x3000+1 will return @retval = count of number of instances found.
Note that nearly all commands will change the value of @retval, so copy it to a variable if you need to keep it, e.g.
available (free) harddisk number not yet recognised by the BIOS. (hd-1) is the last BIOS harddisk.
e.g. If you have 2 hard disks in the system (hd0 and hd1), then ...
If you want to fill a file with the same character or 00 byte, you can fill an area of memory using the memset function first and then use it as if:
map (md)0x300+200 (rd) > nul ;; read 0x82d0 > nul ;; call Fn.24 %@retval% 0x00 102400 > nul dd if=(rd)+1 of=()/ABC.xml
# fill (rd) with 0's , 0x82d0 is rd-base mem address, Fn24 is memset - fill memory <addr> <string> <size> - 200 sectors = 102400 bytes